diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php b/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php index b763774f917308529f724af8b7758887fe0fd5ba..e37fe022342ed5c194914133b9392ef559ff083a 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php @@ -76,6 +76,7 @@ class AdvancedPricing extends \Magento\CatalogImportExport\Model\Export\Product ImportAdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP => '', ImportAdvancedPricing::COL_TIER_PRICE_QTY => '', ImportAdvancedPricing::COL_TIER_PRICE => '', + ImportAdvancedPricing::COL_TIER_PRICE_TYPE => '' ]; /** @@ -279,6 +280,8 @@ class AdvancedPricing extends \Magento\CatalogImportExport\Model\Export\Product } /** + * Correct export data. + * * @param array $exportData * @return array * @SuppressWarnings(PHPMD.UnusedLocalVariable) @@ -302,6 +305,12 @@ class AdvancedPricing extends \Magento\CatalogImportExport\Model\Export\Product : 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 @@ class AdvancedPricing extends \Magento\CatalogImportExport\Model\Export\Product $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 @@ class AdvancedPricing extends \Magento\CatalogImportExport\Model\Export\Product 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 @@ class AdvancedPricing extends \Magento\CatalogImportExport\Model\Export\Product 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 53c4605a819132df0791df60edb325ed5cf5837c..e2275f767ee7ba74ff42528cc6fdb1aa94882c36 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php @@ -33,6 +33,14 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract const COL_TIER_PRICE = 'tier_price'; + const COL_TIER_PRICE_PERCENTAGE_VALUE = 'percentage_value'; + + const COL_TIER_PRICE_TYPE = 'tier_price_value_type'; + + const TIER_PRICE_TYPE_FIXED = 'Fixed'; + + const TIER_PRICE_TYPE_PERCENT = 'Discount'; + const TABLE_TIER_PRICE = 'catalog_product_entity_tier_price'; const DEFAULT_ALL_GROUPS_GROUPED_PRICE_VALUE = '0'; @@ -46,7 +54,7 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract const VALIDATOR_TEAR_PRICE = 'validator_tear_price'; /** - * Validation failure message template definitions + * Validation failure message template definitions. * * @var array */ @@ -57,6 +65,8 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract ValidatorInterface::ERROR_INVALID_TIER_PRICE_QTY => '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 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract $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 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract } } if ($priceIn) { - $this->_connection->insertOnDuplicate($tableName, $priceIn, ['value']); + $this->_connection->insertOnDuplicate($tableName, $priceIn, ['value', 'percentage_value']); } } return $this; diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPrice.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPrice.php index 5bc9bebf420768184c08ea3f2861e5cfcaaf2e21..53ee3013c625beabb7a6f42229a32a9eb7b02eee 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPrice.php +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPrice.php @@ -22,7 +22,8 @@ class TierPrice extends \Magento\CatalogImportExport\Model\Import\Product\Valida AdvancedPricing::COL_TIER_PRICE_WEBSITE, AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP, AdvancedPricing::COL_TIER_PRICE_QTY, - AdvancedPricing::COL_TIER_PRICE + AdvancedPricing::COL_TIER_PRICE, + AdvancedPricing::COL_TIER_PRICE_TYPE ]; /** @@ -101,6 +102,7 @@ class TierPrice extends \Magento\CatalogImportExport\Model\Import\Product\Valida || !isset($value[AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP]) || !isset($value[AdvancedPricing::COL_TIER_PRICE_QTY]) || !isset($value[AdvancedPricing::COL_TIER_PRICE]) + || !isset($value[AdvancedPricing::COL_TIER_PRICE_TYPE]) || $this->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 0000000000000000000000000000000000000000..29982459e0211991427aafa5eddecf88011b899d --- /dev/null +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPriceType.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator; + +use Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing; +use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface; + +/** + * Class TierPriceType validates tier price type. + */ +class TierPriceType extends \Magento\CatalogImportExport\Model\Import\Product\Validator\AbstractImportValidator +{ + /** + * {@inheritdoc} + */ + public function init($context) + { + return parent::init($context); + } + + /** + * Validate tier price type. + * + * @param array $value + * @return bool + */ + public function isValid($value) + { + $isValid = true; + + if (isset($value[AdvancedPricing::COL_TIER_PRICE_TYPE]) + && !empty($value[AdvancedPricing::COL_TIER_PRICE_TYPE]) + && !in_array( + $value[AdvancedPricing::COL_TIER_PRICE_TYPE], + [AdvancedPricing::TIER_PRICE_TYPE_FIXED, AdvancedPricing::TIER_PRICE_TYPE_PERCENT] + ) + ) { + $this->_addMessages([RowValidatorInterface::ERROR_INVALID_TIER_PRICE_TYPE]); + $isValid = false; + } + + return $isValid; + } +} diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/TierPriceTypeTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/TierPriceTypeTest.php new file mode 100644 index 0000000000000000000000000000000000000000..6abdd2232fb44233882e140f61f8020aef145289 --- /dev/null +++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/TierPriceTypeTest.php @@ -0,0 +1,78 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\AdvancedPricingImportExport\Test\Unit\Model\Import\AdvancedPricing\Validator; + +use \Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing as AdvancedPricing; + +/** + * Class TierPriceTypeTest. + */ +class TierPriceTypeTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var AdvancedPricing\Validator\TierPriceType + */ + private $tierPriceType; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->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/AdvancedPricingTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php index a289e9970b4999ee82bde14fdb452ef0d78236df..1c80f5789c38108ae9f94030871602f5628086e1 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php +++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php @@ -418,33 +418,123 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A $groupWebsiteId, $expectedTierPrices ) { - $this->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 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A 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 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A '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 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A '$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 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A 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 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A '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 @@ class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\A $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/etc/di.xml b/app/code/Magento/AdvancedPricingImportExport/etc/di.xml index c3444069c14c0f3f226bad8cf61ef0d5fc092c17..711d4b8b399f5a8709a1fa0760b16c1aad60106f 100644 --- a/app/code/Magento/AdvancedPricingImportExport/etc/di.xml +++ b/app/code/Magento/AdvancedPricingImportExport/etc/di.xml @@ -14,6 +14,7 @@ <argument name="validators" xsi:type="array"> <item name="tierPrice" xsi:type="object">Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator\TierPrice</item> <item name="website" xsi:type="object">Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator\Website</item> + <item name="tierPriceType" xsi:type="object">Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator\TierPriceType</item> </argument> </arguments> </type> diff --git a/app/code/Magento/Catalog/Block/Product/View.php b/app/code/Magento/Catalog/Block/Product/View.php index 8157ab4de07f2a10c9bc5e34541944698f0ab71c..964a444a0aef8b924819598634a0eea36f7ba247 100644 --- a/app/code/Magento/Catalog/Block/Product/View.php +++ b/app/code/Magento/Catalog/Block/Product/View.php @@ -7,7 +7,6 @@ namespace Magento\Catalog\Block\Product; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Category; -use Magento\Catalog\Model\Product; /** * Product View block @@ -29,6 +28,7 @@ class View extends AbstractProduct implements \Magento\Framework\DataObject\Iden /** * @var \Magento\Framework\Pricing\PriceCurrencyInterface + * @deprecated */ protected $priceCurrency; @@ -225,40 +225,34 @@ class View extends AbstractProduct implements \Magento\Framework\DataObject\Iden $config = [ 'productId' => $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/Test/Unit/Ui/DataProvider/Product/Form/Modifier/TierPriceTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/TierPriceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9dccb8eef452ad50e58e04aef1f7273a3fb524a4 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/TierPriceTest.php @@ -0,0 +1,141 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Catalog\Test\Unit\Ui\DataProvider\Product\Form\Modifier; + +use Magento\Catalog\Api\Data\ProductAttributeInterface; +use Magento\Catalog\Model\Config\Source\ProductPriceOptionsInterface; +use Magento\Framework\Stdlib\ArrayManager; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\TierPrice; + +/** + * Class TierPriceTest. + */ +class TierPriceTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var ProductPriceOptionsInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $productPriceOptions; + + /** + * @var ArrayManager|\PHPUnit_Framework_MockObject_MockObject + */ + private $arrayManager; + + /** + * @var TierPrice + */ + private $tierPrice; + + /** + * Set Up. + * @return void + */ + protected function setUp() + { + $this->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/Ui/DataProvider/Product/Form/Modifier/TierPrice.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php new file mode 100644 index 0000000000000000000000000000000000000000..ac511edcf2e5338eba6b83c60cf38a749406cf89 --- /dev/null +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php @@ -0,0 +1,171 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Catalog\Ui\DataProvider\Product\Form\Modifier; + +use Magento\Catalog\Api\Data\ProductAttributeInterface; +use Magento\Catalog\Model\Config\Source\ProductPriceOptionsInterface; +use Magento\Framework\Stdlib\ArrayManager; +use Magento\Ui\Component\Container; +use Magento\Ui\Component\Form\Element\DataType\Price; +use Magento\Ui\Component\Form\Element\Input; +use Magento\Ui\Component\Form\Element\Select; +use Magento\Ui\Component\Form\Field; + +/** + * Tier prices modifier adds price type option to tier prices. + */ +class TierPrice extends AbstractModifier +{ + /** + * @var ProductPriceOptionsInterface + */ + private $productPriceOptions; + + /** + * @var ArrayManager + */ + private $arrayManager; + + /** + * @param ProductPriceOptionsInterface $productPriceOptions + * @param ArrayManager $arrayManager + */ + public function __construct( + ProductPriceOptionsInterface $productPriceOptions, + ArrayManager $arrayManager + ) { + $this->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' => '', + '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/etc/adminhtml/di.xml b/app/code/Magento/Catalog/etc/adminhtml/di.xml index 584a2e51514db53a0250615a55d67455ca1a0f57..5fc5ec8d44fd0a88f8a5d542d5518fa60ad77629 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/di.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/di.xml @@ -142,6 +142,10 @@ <item name="class" xsi:type="string">Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Attributes</item> <item name="sortOrder" xsi:type="number">120</item> </item> + <item name="advanced-pricing-tier-price-type" xsi:type="array"> + <item name="class" xsi:type="string">Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\TierPrice</item> + <item name="sortOrder" xsi:type="number">150</item> + </item> </argument> </arguments> </virtualType> 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 0000000000000000000000000000000000000000..afc0bab3f7fa4baa4dfbb76dc261b0e97672d80e --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/tier-price/percentage-processor.js @@ -0,0 +1,73 @@ +/** + * Copyright © 2016 Magento. 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 0000000000000000000000000000000000000000..216a767d393d57e6596c4d9d75cb7aef0e4a86f7 --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/tier-price/value-type-select.js @@ -0,0 +1,118 @@ +/** + * Copyright © 2016 Magento. 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 0000000000000000000000000000000000000000..b7c18d5332f56347d269dc623ff05c2bff936959 --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/utils/percentage-price-calculator.js @@ -0,0 +1,45 @@ +/** + * Copyright © 2016 Magento. 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/frontend/templates/product/view/addtocart.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml index eacc039255caf98525625e3a18f6dd7e43376e70..ea3e8077d0dc195f42e4cddb78135b6a0d0f9470 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml @@ -20,9 +20,9 @@ <input type="number" name="qty" id="qty" - maxlength="12" value="<?php /* @escapeNotVerified */ echo $block->getProductDefaultQty() * 1 ?>" - title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" class="input-text qty" + title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" + class="input-text qty" data-validate="<?php echo $block->escapeHtml(json_encode($block->getQuantityValidators())) ?>" /> </div> @@ -58,4 +58,4 @@ } } </script> -<?php endif; ?> \ No newline at end of file +<?php endif; ?> diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php index 45cd01bc8252d71711389ae3a837cffb2a846ac0..3f9e157c5710a63c1bb3a47d0462953e96ac48c1 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php @@ -45,6 +45,8 @@ interface RowValidatorInterface extends \Magento\Framework\Validator\ValidatorIn const ERROR_INVALID_TIER_PRICE_GROUP = 'tierPriceGroupInvalid'; + const ERROR_INVALID_TIER_PRICE_TYPE = 'tierPriceTypeInvalid'; + const ERROR_TIER_DATA_INCOMPLETE = 'tierPriceDataIsIncomplete'; const ERROR_SKU_NOT_FOUND_FOR_DELETE = 'skuNotFoundToDelete'; diff --git a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Combine.php b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Combine.php index 283309247cd9d0fbdc9edc8b0cb2bf2d06b2f33c..e40aae5d189b04b9e63911fddbe4813e378fcfa8 100644 --- a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Combine.php +++ b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Combine.php @@ -82,7 +82,7 @@ class Combine extends \Magento\Rule\Model\Condition\Combine public function collectValidatedAttributes($productCollection) { foreach ($this->getConditions() as $condition) { - $condition->addToCollection($productCollection); + $condition->collectValidatedAttributes($productCollection); } return $this; } diff --git a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php index 262ba8f6a6d8dd198da0cb85c87e37a4c1d73795..7d41741135b80498f9b77cc77e4014369efaefc1 100644 --- a/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php +++ b/app/code/Magento/CatalogWidget/Model/Rule/Condition/Product.php @@ -223,4 +223,12 @@ class Product extends \Magento\Rule\Model\Condition\Product\AbstractProduct return $result; } + + /** + * {@inheritdoc} + */ + public function collectValidatedAttributes($productCollection) + { + return $this->addToCollection($productCollection); + } } diff --git a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/CombineTest.php b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/CombineTest.php index fa6474e31e7ccb715c09d1b8d2df5523f2ec9f13..dd42ee1c7c9216fc3749a92c643c4afc972bc233 100644 --- a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/CombineTest.php +++ b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/CombineTest.php @@ -80,9 +80,9 @@ class CombineTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); $condition = $this->getMockBuilder(\Magento\CatalogWidget\Model\Rule\Condition\Combine::class) - ->disableOriginalConstructor()->setMethods(['addToCollection']) + ->disableOriginalConstructor()->setMethods(['collectValidatedAttributes']) ->getMock(); - $condition->expects($this->any())->method('addToCollection')->with($collection) + $condition->expects($this->any())->method('collectValidatedAttributes')->with($collection) ->will($this->returnSelf()); $this->condition->setConditions([$condition]); diff --git a/app/code/Magento/Checkout/Block/Cart/LayoutProcessor.php b/app/code/Magento/Checkout/Block/Cart/LayoutProcessor.php index a492002b0a5a5f55219efe09c3422c39f46e9fee..a042c41634bcb615921b93e01c4c42b23bfb8cd4 100644 --- a/app/code/Magento/Checkout/Block/Cart/LayoutProcessor.php +++ b/app/code/Magento/Checkout/Block/Cart/LayoutProcessor.php @@ -85,14 +85,14 @@ class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcesso 'visible' => true, 'formElement' => 'select', 'label' => __('Country'), - 'options' => $this->countryCollection->loadByStore()->toOptionArray(), + 'options' => [], 'value' => null ], 'region_id' => [ 'visible' => true, 'formElement' => 'select', 'label' => __('State/Province'), - 'options' => $this->regionCollection->load()->toOptionArray(), + 'options' => [], 'value' => null ], 'postcode' => [ @@ -103,6 +103,13 @@ class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcesso ] ]; + if (!isset($jsLayout['components']['checkoutProvider']['dictionaries'])) { + $jsLayout['components']['checkoutProvider']['dictionaries'] = [ + 'country_id' => $this->countryCollection->loadByStore()->toOptionArray(), + 'region_id' => $this->regionCollection->addAllowedCountriesFilter()->toOptionArray(), + ]; + } + if (isset($jsLayout['components']['block-summary']['children']['block-shipping']['children'] ['address-fieldsets']['children']) ) { diff --git a/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php b/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php index 1882d88e04a8b25f51ccf0afbd92a1635f443735..e7686e4bea58b3a5f4db81e1b11f2e17770744c8 100644 --- a/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php +++ b/app/code/Magento/Checkout/Block/Checkout/AttributeMerger.php @@ -192,6 +192,15 @@ class AttributeMerger 'visible' => isset($additionalConfig['visible']) ? $additionalConfig['visible'] : true, ]; + if ($attributeCode === 'region_id' || $attributeCode === 'country_id') { + unset($element['options']); + $element['deps'] = [$providerName]; + $element['imports'] = [ + 'initialOptions' => 'index = ' . $providerName . ':dictionaries.' . $attributeCode, + 'setOptions' => 'index = ' . $providerName . ':dictionaries.' . $attributeCode + ]; + } + if (isset($attributeConfig['value']) && $attributeConfig['value'] != null) { $element['value'] = $attributeConfig['value']; } elseif (isset($attributeConfig['default']) && $attributeConfig['default'] != null) { @@ -341,11 +350,11 @@ class AttributeMerger * @param string $attributeCode * @param array $attributeConfig * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ protected function getFieldOptions($attributeCode, array $attributeConfig) { - $options = isset($attributeConfig['options']) ? $attributeConfig['options'] : []; - return ($attributeCode == 'country_id') ? $this->orderCountryOptions($options) : $options; + return isset($attributeConfig['options']) ? $attributeConfig['options'] : []; } /** @@ -353,6 +362,7 @@ class AttributeMerger * * @param array $countryOptions * @return array + * @deprecated */ protected function orderCountryOptions(array $countryOptions) { diff --git a/app/code/Magento/Checkout/Block/Checkout/DirectoryDataProcessor.php b/app/code/Magento/Checkout/Block/Checkout/DirectoryDataProcessor.php new file mode 100644 index 0000000000000000000000000000000000000000..4a02ebbd079a407e531f17168531a5f9439915fb --- /dev/null +++ b/app/code/Magento/Checkout/Block/Checkout/DirectoryDataProcessor.php @@ -0,0 +1,146 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Block\Checkout; + +use Magento\Directory\Helper\Data as DirectoryHelper; +use Magento\Store\Api\StoreResolverInterface; + +/** + * Directory data processor. + * + * This class adds various country and region dictionaries to checkout page. + * This data can be used by other UI components during checkout flow. + */ +class DirectoryDataProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcessorInterface +{ + /** + * @var array + */ + private $countryOptions; + + /** + * @var array + */ + private $regionOptions; + + /** + * @var \Magento\Directory\Model\ResourceModel\Region\CollectionFactory + */ + private $regionCollectionFactory; + + /** + * @var \Magento\Directory\Model\ResourceModel\Region\CollectionFactory + */ + private $countryCollectionFactory; + + /** + * @var StoreResolverInterface + */ + private $storeResolver; + + /** + * @var DirectoryHelper + */ + private $directoryHelper; + + /** + * @param \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countryCollection + * @param \Magento\Directory\Model\ResourceModel\Region\CollectionFactory $regionCollection + * @param StoreResolverInterface $storeResolver + * @param DirectoryHelper $directoryHelper + */ + public function __construct( + \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countryCollection, + \Magento\Directory\Model\ResourceModel\Region\CollectionFactory $regionCollection, + StoreResolverInterface $storeResolver, + DirectoryHelper $directoryHelper + ) { + $this->countryCollectionFactory = $countryCollection; + $this->regionCollectionFactory = $regionCollection; + $this->storeResolver = $storeResolver; + $this->directoryHelper = $directoryHelper; + } + + /** + * Process js Layout of block + * + * @param array $jsLayout + * @return array + */ + public function process($jsLayout) + { + if (!isset($jsLayout['components']['checkoutProvider']['dictionaries'])) { + $jsLayout['components']['checkoutProvider']['dictionaries'] = [ + 'country_id' => $this->getCountryOptions(), + 'region_id' => $this->getRegionOptions(), + ]; + } + + return $jsLayout; + } + + /** + * Get country options list. + * + * @return array + */ + private function getCountryOptions() + { + if (!isset($this->countryOptions)) { + $this->countryOptions = $this->countryCollectionFactory->create()->loadByStore( + $this->storeResolver->getCurrentStoreId() + )->toOptionArray(); + $this->countryOptions = $this->orderCountryOptions($this->countryOptions); + } + + return $this->countryOptions; + } + + /** + * Get region options list. + * + * @return array + */ + private function getRegionOptions() + { + if (!isset($this->regionOptions)) { + $this->regionOptions = $this->regionCollectionFactory->create()->addAllowedCountriesFilter( + $this->storeResolver->getCurrentStoreId() + )->toOptionArray(); + } + + return $this->regionOptions; + } + + /** + * Sort country options by top country codes. + * + * @param array $countryOptions + * @return array + */ + private function orderCountryOptions(array $countryOptions) + { + $topCountryCodes = $this->directoryHelper->getTopCountryCodes(); + if (empty($topCountryCodes)) { + return $countryOptions; + } + + $headOptions = []; + $tailOptions = [[ + 'value' => 'delimiter', + 'label' => '──────────', + 'disabled' => true, + ]]; + foreach ($countryOptions as $countryOption) { + if (empty($countryOption['value']) || in_array($countryOption['value'], $topCountryCodes)) { + array_push($headOptions, $countryOption); + } else { + array_push($tailOptions, $countryOption); + } + } + return array_merge($headOptions, $tailOptions); + } +} diff --git a/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php b/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php index 1b2c7444198915c866a55ca2cc9b8e6b29544e39..fd8434703ab756a2664e235332d09e13e7890e19 100644 --- a/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php +++ b/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php @@ -7,7 +7,11 @@ namespace Magento\Checkout\Block\Checkout; use Magento\Checkout\Helper\Data; use Magento\Framework\App\ObjectManager; +use Magento\Store\Api\StoreResolverInterface; +/** + * Class LayoutProcessor + */ class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcessorInterface { /** @@ -35,6 +39,16 @@ class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcesso */ private $checkoutDataHelper; + /** + * @var StoreResolverInterface + */ + private $storeResolver; + + /** + * @var \Magento\Shipping\Model\Config + */ + private $shippingConfig; + /** * @param \Magento\Customer\Model\AttributeMetadataDataProvider $attributeMetadataDataProvider * @param \Magento\Ui\Component\Form\AttributeMapper $attributeMapper @@ -146,6 +160,16 @@ class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcesso $elements ); } + if (isset($jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children'] + ['step-config']['children']['shipping-rates-validation']['children'] + )) { + $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children'] + ['step-config']['children']['shipping-rates-validation']['children'] = + $this->processShippingChildrenComponents( + $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children'] + ['step-config']['children']['shipping-rates-validation']['children'] + ); + } if (isset($jsLayout['components']['checkout']['children']['steps']['children']['shipping-step'] ['children']['shippingAddress']['children']['shipping-address-fieldset']['children'] @@ -163,6 +187,26 @@ class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcesso return $jsLayout; } + /** + * Process shipping configuration to exclude inactive carriers. + * + * @param array $shippingRatesLayout + * @return array + */ + private function processShippingChildrenComponents($shippingRatesLayout) + { + $activeCarriers = $this->getShippingConfig()->getActiveCarriers( + $this->getStoreResolver()->getCurrentStoreId() + ); + foreach (array_keys($shippingRatesLayout) as $carrierName) { + $carrierKey = str_replace('-rates-validation', '', $carrierName); + if (!array_key_exists($carrierKey, $activeCarriers)) { + unset($shippingRatesLayout[$carrierName]); + } + } + return $shippingRatesLayout; + } + /** * Appends billing address form component to payment layout * @param array $paymentLayout @@ -314,4 +358,34 @@ class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcesso return $this->checkoutDataHelper; } + + /** + * Retrieve Shipping Configuration. + * + * @return \Magento\Shipping\Model\Config + * @deprecated + */ + private function getShippingConfig() + { + if (!$this->shippingConfig) { + $this->shippingConfig = ObjectManager::getInstance()->get(\Magento\Shipping\Model\Config::class); + } + + return $this->shippingConfig; + } + + /** + * Get store resolver. + * + * @return StoreResolverInterface + * @deprecated + */ + private function getStoreResolver() + { + if (!$this->storeResolver) { + $this->storeResolver = ObjectManager::getInstance()->get(StoreResolverInterface::class); + } + + return $this->storeResolver; + } } diff --git a/app/code/Magento/Checkout/Test/Unit/Block/Cart/LayoutProcessorTest.php b/app/code/Magento/Checkout/Test/Unit/Block/Cart/LayoutProcessorTest.php index 95ffed86cbb35177051303726222813942336c72..5eabb6c9c86a47def05a69762c21f0b47f5a608f 100644 --- a/app/code/Magento/Checkout/Test/Unit/Block/Cart/LayoutProcessorTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Block/Cart/LayoutProcessorTest.php @@ -69,7 +69,7 @@ class LayoutProcessorTest extends \PHPUnit_Framework_TestCase $this->countryCollection->expects($this->once())->method('loadByStore')->willReturnSelf(); $this->countryCollection->expects($this->once())->method('toOptionArray')->willReturn($countries); - $this->regionCollection->expects($this->once())->method('load')->willReturnSelf(); + $this->regionCollection->expects($this->once())->method('addAllowedCountriesFilter')->willReturnSelf(); $this->regionCollection->expects($this->once())->method('toOptionArray')->willReturn($regions); $layoutMerged = $layout; @@ -77,7 +77,12 @@ class LayoutProcessorTest extends \PHPUnit_Framework_TestCase ['address-fieldsets']['children']['fieldThree'] = ['param' => 'value']; $layoutMergedPointer = &$layoutMerged['components']['block-summary']['children']['block-shipping'] ['children']['address-fieldsets']['children']; - + $layoutMerged['components']['checkoutProvider'] = [ + 'dictionaries' => [ + 'country_id' => [], + 'region_id' => [], + ] + ]; $elements = [ 'city' => [ 'visible' => false, diff --git a/app/code/Magento/Checkout/Test/Unit/Block/Checkout/DirectoryDataProcessorTest.php b/app/code/Magento/Checkout/Test/Unit/Block/Checkout/DirectoryDataProcessorTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c84fac464c047ad611268d26ac988adb2b419596 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Unit/Block/Checkout/DirectoryDataProcessorTest.php @@ -0,0 +1,114 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Checkout\Test\Unit\Block\Checkout; + +class DirectoryDataProcessorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Checkout\Block\Checkout\DirectoryDataProcessor + */ + protected $model; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $countryCollectionFactoryMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $countryCollectionMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $regionCollectionFactoryMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $regionCollectionMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $storeResolverMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $directoryDataHelperMock; + + protected function setUp() + { + $this->countryCollectionFactoryMock = $this->getMock( + \Magento\Directory\Model\ResourceModel\Country\CollectionFactory::class, + ['create'], + [], + '', + false + ); + $this->countryCollectionMock = $this->getMock( + \Magento\Directory\Model\ResourceModel\Country\Collection::class, + [], + [], + '', + false + ); + $this->regionCollectionFactoryMock = $this->getMock( + \Magento\Directory\Model\ResourceModel\Region\CollectionFactory::class, + ['create'], + [], + '', + false + ); + $this->regionCollectionMock = $this->getMock( + \Magento\Directory\Model\ResourceModel\Region\Collection::class, + [], + [], + '', + false + ); + $this->storeResolverMock = $this->getMock( + \Magento\Store\Api\StoreResolverInterface::class + ); + $this->directoryDataHelperMock = $this->getMock( + \Magento\Directory\Helper\Data::class, + [], + [], + '', + false + ); + + $this->model = new \Magento\Checkout\Block\Checkout\DirectoryDataProcessor( + $this->countryCollectionFactoryMock, + $this->regionCollectionFactoryMock, + $this->storeResolverMock, + $this->directoryDataHelperMock + ); + } + + public function testProcess() + { + $expectedResult['components']['checkoutProvider']['dictionaries'] = [ + 'country_id' => [], + 'region_id' => [], + ]; + + $this->countryCollectionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->countryCollectionMock); + $this->countryCollectionMock->expects($this->once())->method('loadByStore')->willReturnSelf(); + $this->countryCollectionMock->expects($this->once())->method('toOptionArray')->willReturn([]); + $this->regionCollectionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->regionCollectionMock); + $this->regionCollectionMock->expects($this->once())->method('addAllowedCountriesFilter')->willReturnSelf(); + $this->regionCollectionMock->expects($this->once())->method('toOptionArray')->willReturn([]); + + $this->assertEquals($expectedResult, $this->model->process([])); + } +} diff --git a/app/code/Magento/Checkout/Test/Unit/Block/Checkout/LayoutProcessorTest.php b/app/code/Magento/Checkout/Test/Unit/Block/Checkout/LayoutProcessorTest.php index 1351213f990b54a573a5d5d3a015e7b940a5f7ee..95aed9b56afc33d2f08f778a2e4b1e2162d35fe6 100644 --- a/app/code/Magento/Checkout/Test/Unit/Block/Checkout/LayoutProcessorTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Block/Checkout/LayoutProcessorTest.php @@ -17,6 +17,8 @@ use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * LayoutProcessorTest covers a list of variations for * checkout layout processor + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class LayoutProcessorTest extends \PHPUnit_Framework_TestCase { @@ -45,6 +47,11 @@ class LayoutProcessorTest extends \PHPUnit_Framework_TestCase */ private $layoutProcessor; + /** + * @var MockObject + */ + private $storeResolver; + protected function setUp() { $objectManager = new ObjectManager($this); @@ -79,8 +86,11 @@ class LayoutProcessorTest extends \PHPUnit_Framework_TestCase $this->attributeMerger ); + $this->storeResolver = $this->getMock(\Magento\Store\Api\StoreResolverInterface::class); + $objectManager->setBackwardCompatibleProperty($this->layoutProcessor, 'checkoutDataHelper', $this->dataHelper); $objectManager->setBackwardCompatibleProperty($this->layoutProcessor, 'options', $options); + $objectManager->setBackwardCompatibleProperty($this->layoutProcessor, 'storeResolver', $this->storeResolver); } /** diff --git a/app/code/Magento/Checkout/etc/frontend/di.xml b/app/code/Magento/Checkout/etc/frontend/di.xml index 6fb9058c3b7681c8905a40a5eace5d88d8566b6f..69ed33721740d680ec6662e43858e9c42a1c6629 100644 --- a/app/code/Magento/Checkout/etc/frontend/di.xml +++ b/app/code/Magento/Checkout/etc/frontend/di.xml @@ -55,6 +55,7 @@ <argument name="layoutProcessors" xsi:type="array"> <item name="addressFormAttributes" xsi:type="object">Magento\Checkout\Block\Checkout\LayoutProcessor</item> <item name="totalsSortOrder" xsi:type="object">Magento\Checkout\Block\Checkout\TotalsProcessor</item> + <item name="directoryData" xsi:type="object">Magento\Checkout\Block\Checkout\DirectoryDataProcessor</item> </argument> </arguments> </type> diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml index 0f221a393f5eb181f31a778ce4d01da1b0cc109b..ebe8f4570b02f39ca9acb39986d72b5c402b496d 100644 --- a/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml +++ b/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml @@ -17,7 +17,13 @@ <div class="field qty"> <label class="label" for="qty"><span><?php /* @escapeNotVerified */ echo __('Qty') ?></span></label> <div class="control"> - <input type="number" name="qty" id="qty" maxlength="12" value="" title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" class="input-text qty" data-validate="{'required-number':true,digits:true}"/> + <input type="number" + name="qty" + id="qty" + value="" + title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" + class="input-text qty" + data-validate="{'required-number':true,digits:true}"/> </div> </div> <?php endif; ?> diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml index d83b552b05cd4be4e55262bfb4c56a86039113c6..21fafe4d37f1b2496f421026c410e974972bc59d 100644 --- a/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml +++ b/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml @@ -96,7 +96,6 @@ $canApplyMsrp = $helper->isShowBeforeOrderConfirm($product) && $helper->isMinima size="4" title="<?php echo $block->escapeHtml(__('Qty')); ?>" class="input-text qty" - maxlength="12" data-validate="{required:true,'validate-greater-than-zero':true}" data-role="cart-item-qty"/> </div> diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js b/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js index 9a3685b212b435e8c03adb7be2cd7a182e591b87..c215b1989edbeafe273819b09f2588f06169b4e5 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js @@ -10,13 +10,13 @@ define([], function () { * Returns new address object */ return function (addressData) { - var identifier = Date.now(); - var regionId = null; + var identifier = Date.now(), + regionId; if (addressData.region && addressData.region.region_id) { regionId = addressData.region.region_id; } else if (addressData.country_id && addressData.country_id == window.checkoutConfig.defaultCountryId) { - regionId = window.checkoutConfig.defaultRegionId; + regionId = window.checkoutConfig.defaultRegionId || undefined; } return { @@ -25,7 +25,7 @@ define([], function () { regionId: regionId || addressData.regionId, regionCode: (addressData.region) ? addressData.region.region_code : null, region: (addressData.region) ? addressData.region.region : null, - customerId: addressData.customer_id, + customerId: addressData.customer_id || addressData.customerId, street: addressData.street, company: addressData.company, telephone: addressData.telephone, diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/cart/shipping-estimation.js b/app/code/Magento/Checkout/view/frontend/web/js/view/cart/shipping-estimation.js index 08641f015f609a9b8c75e80e0cfd39a82a6f5b1e..cd43dc646584d52708f3923c042889fdb20e0d82 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/cart/shipping-estimation.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/cart/shipping-estimation.js @@ -50,9 +50,13 @@ define( if (address) { estimatedAddress = address.isEditable() ? addressConverter.quoteAddressToFormAddressData(address) : - addressConverter.quoteAddressToFormAddressData( - addressConverter.addressToEstimationAddress(address) - ); + { + // only the following fields must be used by estimation form data provider + 'country_id': address.countryId, + region: address.region, + 'region_id': address.regionId, + postcode: address.postcode + }; checkoutProvider.set( 'shippingAddress', $.extend({}, checkoutProvider.get('shippingAddress'), estimatedAddress) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js index 8910e41731d11a9be99bf1777dc13e3550781976..fb15e47eaf7d487da1c8671c545f0b99ce2a7445 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js @@ -79,7 +79,6 @@ define( fieldsetName = 'checkout.steps.shipping-step.shippingAddress.shipping-address-fieldset'; this._super(); - shippingRatesValidator.initFields(fieldsetName); if (!quote.isVirtual()) { stepNavigator.registerStep( @@ -120,6 +119,7 @@ define( checkoutProvider.on('shippingAddress', function (shippingAddressData) { checkoutData.setShippingAddressFromData(shippingAddressData); }); + shippingRatesValidator.initFields(fieldsetName); }); return this; diff --git a/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html b/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html index 89789996e5248bb8ffec2ac9db18b52eec315d56..8796152eb60315266d870682924f44789c2f5dc7 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html @@ -79,8 +79,7 @@ }, value: qty" type="number" size="4" - class="item-qty cart-item-qty" - maxlength="12"/> + class="item-qty cart-item-qty"> <button data-bind="attr: { id: 'update-cart-item-'+item_id, 'data-cart-item': item_id, diff --git a/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php index 1cc1cceefb39972cfc09d2c7f70463d2f3f76da7..51c68145b24cf5e72061a51647d4b311f39e60bf 100644 --- a/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php @@ -92,6 +92,18 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView ); } + /** + * Get cache key informative items. + * + * @return array + */ + public function getCacheKeyInfo() + { + $parentData = parent::getCacheKeyInfo(); + $parentData[] = $this->priceCurrency->getCurrencySymbol(); + return $parentData; + } + /** * Get allowed attributes * 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 f6740550efca6556490481a9c6c0516d21b9b4e2..a96dca0002d69d30fd0aab7372020e787383512e 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 @@ -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/address.js b/app/code/Magento/Customer/view/frontend/web/js/model/customer/address.js index 30fbef98fd39ab15db1c7971e3e86ad82e367253..e013a96e4890aee11d30641a2f2ee31c4e6088c2 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 @@ -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/Directory/Model/ResourceModel/Region/Collection.php b/app/code/Magento/Directory/Model/ResourceModel/Region/Collection.php index 718e0c0223d767dd3857f5c796d9b7f9d918900a..3fdb20165d4bea912e42c94e14c5c0b3e01cdf8e 100644 --- a/app/code/Magento/Directory/Model/ResourceModel/Region/Collection.php +++ b/app/code/Magento/Directory/Model/ResourceModel/Region/Collection.php @@ -9,6 +9,14 @@ */ namespace Magento\Directory\Model\ResourceModel\Region; +use Magento\Directory\Model\AllowedCountries; +use Magento\Framework\App\ObjectManager; +use Magento\Store\Model\ScopeInterface; + +/** + * Class Collection + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection { /** @@ -30,6 +38,11 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\Ab */ protected $_localeResolver; + /** + * @var AllowedCountries + */ + private $allowedCountriesReader; + /** * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory * @param \Psr\Log\LoggerInterface $logger @@ -89,6 +102,40 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\Ab return $this; } + /** + * Return Allowed Countries reader + * + * @return \Magento\Directory\Model\AllowedCountries + * @deprecated + */ + private function getAllowedCountriesReader() + { + if (!$this->allowedCountriesReader) { + $this->allowedCountriesReader = ObjectManager::getInstance()->get(AllowedCountries::class); + } + + return $this->allowedCountriesReader; + } + + /** + * Set allowed countries filter based on the given store. + * This is a convenience method for collection filtering based on store configuration settings. + * + * @param null|int|string|\Magento\Store\Model\Store $store + * @return \Magento\Directory\Model\ResourceModel\Region\Collection + */ + public function addAllowedCountriesFilter($store = null) + { + $allowedCountries = $this->getAllowedCountriesReader() + ->getAllowedCountries(ScopeInterface::SCOPE_STORE, $store); + + if (!empty($allowedCountries)) { + $this->addFieldToFilter('main_table.country_id', ['in' => $allowedCountries]); + } + + return $this; + } + /** * Filter by country_id * diff --git a/app/code/Magento/Directory/Test/Unit/Model/ResourceModel/Region/CollectionTest.php b/app/code/Magento/Directory/Test/Unit/Model/ResourceModel/Region/CollectionTest.php index 59c054b00a5f9c11607ca2126c0e0174918785e6..5c09ab119295a4e511f99f80f8320950a2a8ff57 100644 --- a/app/code/Magento/Directory/Test/Unit/Model/ResourceModel/Region/CollectionTest.php +++ b/app/code/Magento/Directory/Test/Unit/Model/ResourceModel/Region/CollectionTest.php @@ -6,6 +6,7 @@ namespace Magento\Directory\Test\Unit\Model\ResourceModel\Region; use Magento\Directory\Model\ResourceModel\Region\Collection; +use Magento\Directory\Model\AllowedCountries; use Magento\Framework\DB\Adapter\Pdo\Mysql; use Magento\Framework\DB\Select; use Magento\Framework\Model\ResourceModel\Db\AbstractDb; @@ -15,7 +16,14 @@ use Magento\Framework\Data\Collection\EntityFactory; use Magento\Framework\Locale\ResolverInterface; use Magento\Framework\DataObject; use Psr\Log\LoggerInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use PHPUnit_Framework_MockObject_MockObject as MockObject; +/** + * Class CollectionTest + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class CollectionTest extends \PHPUnit_Framework_TestCase { /** @@ -23,15 +31,22 @@ class CollectionTest extends \PHPUnit_Framework_TestCase */ private $collection; + /** + * @var MockObject + */ + private $allowedCountries; + protected function setUp() { + $objectManager = new ObjectManager($this); $entityFactoryMock = $this->getMock(EntityFactory::class, [], [], '', false); $loggerMock = $this->getMock(LoggerInterface::class); $fetchStrategyMock = $this->getMock(FetchStrategyInterface::class); $eventManagerMock = $this->getMock(ManagerInterface::class); $localeResolverMock = $this->getMock(ResolverInterface::class); $connectionMock = $this->getMock(Mysql::class, [], [], '', false); - $resourceMock = $this->getMockForAbstractClass(AbstractDb::class, + $resourceMock = $this->getMockForAbstractClass( + AbstractDb::class, [], '', false, @@ -39,6 +54,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase true, ['getConnection', 'getMainTable', 'getTable', '__wakeup'] ); + $this->allowedCountries = $this->getMock(AllowedCountries::class, [], [], '', false); $selectMock = $this->getMock(Select::class, [], [], '', false); $connectionMock->expects($this->any())->method('select')->will($this->returnValue($selectMock)); @@ -54,6 +70,12 @@ class CollectionTest extends \PHPUnit_Framework_TestCase $connectionMock, $resourceMock ); + + $objectManager->setBackwardCompatibleProperty( + $this->collection, + 'allowedCountriesReader', + $this->allowedCountries + ); } public function testToOptionArray() @@ -98,4 +120,14 @@ class CollectionTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expectedResult, $this->collection->toOptionArray()); } + + public function testAddAllowedCountriesFilter() + { + $allowedCountries = [1, 2, 3]; + $this->allowedCountries->expects($this->once())->method('getAllowedCountries')->with( + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + null + )->willReturn($allowedCountries); + $this->assertEquals($this->collection->addAllowedCountriesFilter(), $this->collection); + } } diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php index 0d8d18df223767b2812f58356de3b7904090d8f7..1841a9efb6cf8424ebc7ef0b289495388da31db2 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php @@ -8,6 +8,7 @@ namespace Magento\Eav\Model\Entity\Attribute; use Magento\Framework\Api\AttributeValueFactory; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Serialize\SerializerInterface; /** * Entity/Attribute/Model - attribute abstract @@ -22,6 +23,11 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens { const TYPE_STATIC = 'static'; + /** + * Const for empty string value. + */ + const EMPTY_STRING = ''; + /** * Attribute name * @@ -111,6 +117,27 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens */ protected $dataObjectHelper; + /** + * Serializer Instance. + * + * @var SerializerInterface + */ + private $serializer; + + /** + * Array of attribute types that have empty string as a possible value. + * + * @var array + */ + private $emptyStringTypes = [ + 'int', + 'decimal', + 'datetime', + 'varchar', + 'text', + 'static', + ]; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -166,6 +193,21 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens $this->dataObjectHelper = $dataObjectHelper; } + /** + * Get Serializer instance. + * @deprecated + * + * @return SerializerInterface + */ + private function getSerializer() + { + if ($this->serializer === null) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance()->create(SerializerInterface::class); + } + + return $this->serializer; + } + /** * Initialize resource model * @@ -202,6 +244,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens $this->_getResource()->loadByCode($this, $entityTypeId, $code); $this->_afterLoad(); \Magento\Framework\Profiler::stop('load_by_code'); + return $this; } @@ -226,6 +269,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens public function setAttributeId($data) { $this->_data['attribute_id'] = $data; + return $this; } @@ -372,6 +416,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens public function setAttributeSetId($id) { $this->_data['attribute_set_id'] = $id; + return $this; } @@ -392,6 +437,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens public function setEntityTypeId($id) { $this->_data['entity_type_id'] = $id; + return $this; } @@ -403,6 +449,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens public function setEntityType($type) { $this->setData('entity_type', $type); + return $this; } @@ -456,6 +503,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens public function setEntity($entity) { $this->_entity = $entity; + return $this; } @@ -469,6 +517,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens if (!$this->_entity) { $this->_entity = $this->getEntityType(); } + return $this->_entity; } @@ -546,6 +595,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens } $this->_source = $source->setAttribute($this); } + return $this->_source; } @@ -557,6 +607,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens public function usesSource() { $input = $this->getFrontendInput(); + return $input === 'select' || $input === 'multiselect' || $this->_getData('source_model') != ''; } @@ -588,17 +639,38 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens } /** + * Check if Value is empty. + * * @param array|null|bool|int|float|string $value * @return bool */ public function isValueEmpty($value) { - /** @var array $emptyStringTypes list of attribute types that treat empty string as a possible value */ - $emptyStringTypes = ['int', 'decimal', 'datetime', 'varchar', 'text', 'static']; return (is_array($value) && count($value) == 0) || $value === null || ($value === false && $this->getBackend()->getType() != 'int') - || ($value === '' && in_array($this->getBackend()->getType(), $emptyStringTypes)); + || ($value === self::EMPTY_STRING && $this->isInEmptyStringTypes()); + } + + /** + * Check if attribute empty value is valid. + * + * @param array|null|bool|int|float|string $value + * @return bool + */ + public function isAllowedEmptyTextValue($value) + { + return $this->isInEmptyStringTypes() && $value === self::EMPTY_STRING; + } + + /** + * Check is attribute type in allowed empty string types. + * + * @return bool + */ + private function isInEmptyStringTypes() + { + return in_array($this->getBackend()->getType(), $this->emptyStringTypes); } /** @@ -654,6 +726,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens if (!isset($this->_attributeIdCache[$cacheKey])) { $this->_attributeIdCache[$cacheKey] = $this->getResource()->getIdByCode($entityType, $code); } + return $this->_attributeIdCache[$cacheKey]; } @@ -686,6 +759,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens $this->_dataTable = $backendTable; } } + return $this->_dataTable; } @@ -700,6 +774,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens if ($this->usesSource() && $this->getBackendType() != self::TYPE_STATIC) { return $this->getSource()->getFlatColumns(); } + return $this->_getFlatColumnsDdlDefinition(); } @@ -723,60 +798,60 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens $size = $prop['LENGTH'] ? $prop['LENGTH'] : null; $columns[$this->getAttributeCode()] = [ - 'type' => $this->_resourceHelper->getDdlTypeByColumnType($type), - 'length' => $size, + 'type' => $this->_resourceHelper->getDdlTypeByColumnType($type), + 'length' => $size, 'unsigned' => $prop['UNSIGNED'] ? true : false, 'nullable' => $prop['NULLABLE'], - 'default' => $prop['DEFAULT'], - 'extra' => null, + 'default' => $prop['DEFAULT'], + 'extra' => null, ]; break; case 'datetime': $columns[$this->getAttributeCode()] = [ - 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_DATETIME, + 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_DATETIME, 'unsigned' => false, 'nullable' => true, - 'default' => null, - 'extra' => null, + 'default' => null, + 'extra' => null, ]; break; case 'decimal': $columns[$this->getAttributeCode()] = [ - 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL, - 'length' => '12,4', + 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL, + 'length' => '12,4', 'unsigned' => false, 'nullable' => true, - 'default' => null, - 'extra' => null, + 'default' => null, + 'extra' => null, ]; break; case 'int': $columns[$this->getAttributeCode()] = [ - 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, 'unsigned' => false, 'nullable' => true, - 'default' => null, - 'extra' => null, + 'default' => null, + 'extra' => null, ]; break; case 'text': $columns[$this->getAttributeCode()] = [ - 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 'unsigned' => false, 'nullable' => true, - 'default' => null, - 'extra' => null, - 'length' => \Magento\Framework\DB\Ddl\Table::MAX_TEXT_SIZE, + 'default' => null, + 'extra' => null, + 'length' => \Magento\Framework\DB\Ddl\Table::MAX_TEXT_SIZE, ]; break; case 'varchar': $columns[$this->getAttributeCode()] = [ - 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 'length' => '255', + 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + 'length' => '255', 'unsigned' => false, 'nullable' => true, - 'default' => null, - 'extra' => null, + 'default' => null, + 'extra' => null, ]; break; default: @@ -804,61 +879,62 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens } $prop = $describe[$this->getAttributeCode()]; $columns[$this->getAttributeCode()] = [ - 'type' => $prop['DATA_TYPE'] . ($prop['LENGTH'] ? "({$prop['LENGTH']})" : ""), + 'type' => $prop['DATA_TYPE'] . ($prop['LENGTH'] ? "({$prop['LENGTH']})" : ""), 'unsigned' => $prop['UNSIGNED'] ? true : false, - 'is_null' => $prop['NULLABLE'], - 'default' => $prop['DEFAULT'], - 'extra' => null, + 'is_null' => $prop['NULLABLE'], + 'default' => $prop['DEFAULT'], + 'extra' => null, ]; break; case 'datetime': $columns[$this->getAttributeCode()] = [ - 'type' => 'datetime', + 'type' => 'datetime', 'unsigned' => false, - 'is_null' => true, - 'default' => null, - 'extra' => null, + 'is_null' => true, + 'default' => null, + 'extra' => null, ]; break; case 'decimal': $columns[$this->getAttributeCode()] = [ - 'type' => 'decimal(12,4)', + 'type' => 'decimal(12,4)', 'unsigned' => false, - 'is_null' => true, - 'default' => null, - 'extra' => null, + 'is_null' => true, + 'default' => null, + 'extra' => null, ]; break; case 'int': $columns[$this->getAttributeCode()] = [ - 'type' => 'int', + 'type' => 'int', 'unsigned' => false, - 'is_null' => true, - 'default' => null, - 'extra' => null, + 'is_null' => true, + 'default' => null, + 'extra' => null, ]; break; case 'text': $columns[$this->getAttributeCode()] = [ - 'type' => 'text', + 'type' => 'text', 'unsigned' => false, - 'is_null' => true, - 'default' => null, - 'extra' => null, + 'is_null' => true, + 'default' => null, + 'extra' => null, ]; break; case 'varchar': $columns[$this->getAttributeCode()] = [ - 'type' => 'varchar(255)', + 'type' => 'varchar(255)', 'unsigned' => false, - 'is_null' => true, - 'default' => null, - 'extra' => null, + 'is_null' => true, + 'default' => null, + 'extra' => null, ]; break; default: break; } + return $columns; } @@ -945,6 +1021,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens foreach ($this->_storeManager->getStores() as $store) { $this->getFlatUpdateSelect($store->getId()); } + return $this; } @@ -955,6 +1032,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens if ($this->usesSource()) { return $this->getSource()->getFlatUpdateSelect($store); } + return $this->_getResource()->getFlatUpdateSelect($this, $store); } @@ -1064,6 +1142,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens } else { $this->setData(self::OPTIONS, $options); } + return $this; } @@ -1086,6 +1165,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens ); $dataObjects[] = $optionDataObject; } + return $dataObjects; } @@ -1195,8 +1275,9 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens if (is_array($rules)) { return $rules; } elseif (!empty($rules)) { - return unserialize($rules); + return $this->getSerializer()->unserialize($rules); } + return []; } diff --git a/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php b/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php index c775a24a03c465dad45640a7f634823cb8b43ef8..bcaf11aaf5532be296fe19ac6d0bb451b6a20b13 100644 --- a/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php +++ b/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php @@ -125,55 +125,65 @@ class UpdateHandler implements AttributeInterface : null; // @todo verify is it normal to not have attributer_set_id $snapshot = $this->readSnapshot->execute($entityType, $entityDataForSnapshot); foreach ($this->getAttributes($entityType, $attributeSetId) as $attribute) { - if ($attribute->isStatic()) { - continue; - } - /** - * Only scalar values can be stored in generic tables - */ - if (isset($entityData[$attribute->getAttributeCode()]) - && !is_scalar($entityData[$attribute->getAttributeCode()])) { + $code = $attribute->getAttributeCode(); + $isAllowedValueType = array_key_exists($code, $entityData) + && (is_scalar($entityData[$code]) || $entityData[$code] === null); + + if ($attribute->isStatic() || !$isAllowedValueType) { continue; } - if (isset($snapshot[$attribute->getAttributeCode()]) - && $snapshot[$attribute->getAttributeCode()] !== false - && (array_key_exists($attribute->getAttributeCode(), $entityData) - && $attribute->isValueEmpty($entityData[$attribute->getAttributeCode()])) - ) { - $this->attributePersistor->registerDelete( - $entityType, - $entityData[$metadata->getLinkField()], - $attribute->getAttributeCode() - ); - } - if ((!array_key_exists($attribute->getAttributeCode(), $snapshot) - || $snapshot[$attribute->getAttributeCode()] === false) - && array_key_exists($attribute->getAttributeCode(), $entityData) - && !$attribute->isValueEmpty($entityData[$attribute->getAttributeCode()]) - ) { - $this->attributePersistor->registerInsert( - $entityType, - $entityData[$metadata->getLinkField()], - $attribute->getAttributeCode(), - $entityData[$attribute->getAttributeCode()] - ); - } - if (array_key_exists($attribute->getAttributeCode(), $snapshot) - && $snapshot[$attribute->getAttributeCode()] !== false - && array_key_exists($attribute->getAttributeCode(), $entityData) - && $snapshot[$attribute->getAttributeCode()] != $entityData[$attribute->getAttributeCode()] - && !$attribute->isValueEmpty($entityData[$attribute->getAttributeCode()]) - ) { - $this->attributePersistor->registerUpdate( - $entityType, - $entityData[$metadata->getLinkField()], - $attribute->getAttributeCode(), - $entityData[$attribute->getAttributeCode()] - ); + + $newValue = $entityData[$code]; + $isValueEmpty = $attribute->isValueEmpty($newValue); + $isAllowedEmptyStringValue = $attribute->isAllowedEmptyTextValue($newValue); + + if (array_key_exists($code, $snapshot)) { + $snapshotValue = $snapshot[$code]; + /** + * 'FALSE' value for attributes can't be update or delete + */ + if ($snapshotValue === false) { + continue; + } + + if (!$isValueEmpty || $isAllowedEmptyStringValue) { + /** + * NOT Updated value for attributes not need to update + */ + if ($snapshotValue === $newValue) { + continue; + } + + $this->attributePersistor->registerUpdate( + $entityType, + $entityData[$metadata->getLinkField()], + $code, + $newValue + ); + } else { + $this->attributePersistor->registerDelete( + $entityType, + $entityData[$metadata->getLinkField()], + $code + ); + } + } else { + /** + * Only not empty value of attribute is insertable + */ + if (!$isValueEmpty || $isAllowedEmptyStringValue) { + $this->attributePersistor->registerInsert( + $entityType, + $entityData[$metadata->getLinkField()], + $code, + $newValue + ); + } } } $this->attributePersistor->flush($entityType, $context); } + return $this->getReadHandler()->execute($entityType, $entityData, $arguments); } @@ -189,6 +199,7 @@ class UpdateHandler implements AttributeInterface if (!$this->readHandler) { $this->readHandler = ObjectManager::getInstance()->get(ReadHandler::class); } + return $this->readHandler; } } diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php index a10bafacda42dc2b72fcc285307a0250cae3074b..3c0e77408ba2dfbbe68651107cfa1a1d7a885588 100644 --- a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php +++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php @@ -144,19 +144,33 @@ class AbstractAttributeTest extends \PHPUnit_Framework_TestCase public function testGetValidationRulesWhenRuleIsSerialized() { - $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $rule = 'some value'; - $model = $objectManagerHelper->getObject( - \Magento\Catalog\Model\Entity\Attribute::class, - [ - 'data' => [ - \Magento\Eav\Api\Data\AttributeInterface::VALIDATE_RULES => serialize($rule) - ] + $rule = serialize('some value'); + $expected = 'some test result'; - ] - ); + $modelClassName = \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class; + $model = $this->getMockForAbstractClass($modelClassName, [], '', false); - $this->assertEquals($rule, $model->getValidationRules()); + $serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); + + $reflection = new \ReflectionClass($modelClassName); + $reflectionProperty = $reflection->getProperty('serializer'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($model, $serializerMock); + + $model->setData(\Magento\Eav\Api\Data\AttributeInterface::VALIDATE_RULES, $rule); + + $serializerMock->method('unserialize') + ->with($rule) + ->willReturn($expected); + + $this->assertEquals($expected, $model->getValidationRules()); + + $data = ['test array']; + $model->setData(\Magento\Eav\Api\Data\AttributeInterface::VALIDATE_RULES, $data); + $this->assertEquals($data, $model->getValidationRules()); + + $model->setData(\Magento\Eav\Api\Data\AttributeInterface::VALIDATE_RULES, null); + $this->assertEquals([], $model->getValidationRules()); } public function testGetValidationRulesWhenRuleIsEmpty() diff --git a/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml b/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml index 58fbb4511e54ca06afdf0d3f8c864bb9e1a8bee4..05428e248b69c996af9c0863e9d48ca261777538 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml +++ b/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml @@ -46,9 +46,9 @@ <td data-th="<?php echo $block->escapeHtml(__('Qty')); ?>" class="col qty"> <?php if ($_item->isSaleable()) : ?> <div class="control qty"> - <input type="number" name="super_group[<?php /* @escapeNotVerified */ echo $_item->getId() ?>]" + <input type="number" + name="super_group[<?php /* @escapeNotVerified */ echo $_item->getId() ?>]" data-selector="super_group[<?php /* @escapeNotVerified */ echo $_item->getId() ?>]" - maxlength="12" value="<?php /* @escapeNotVerified */ echo $_item->getQty() * 1 ?>" title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" class="input-text qty" diff --git a/app/code/Magento/ImportExport/Block/Adminhtml/Export/Filter.php b/app/code/Magento/ImportExport/Block/Adminhtml/Export/Filter.php index 2f054b5a9c4d10c93dd83193493ae35cd4f00a48..6d3f8b763026cd0514b6c87b4dc898717bc75ee0 100644 --- a/app/code/Magento/ImportExport/Block/Adminhtml/Export/Filter.php +++ b/app/code/Magento/ImportExport/Block/Adminhtml/Export/Filter.php @@ -6,6 +6,7 @@ namespace Magento\ImportExport\Block\Adminhtml\Export; use Magento\Eav\Model\Entity\Attribute; +use Magento\Catalog\Api\Data\ProductAttributeInterface; /** * Export filter block @@ -185,25 +186,39 @@ class Filter extends \Magento\Backend\Block\Widget\Grid\Extended $toValue = $this->escapeHtml(next($value)); } - return '<strong class="admin__control-support-text">' . __( - 'From' - ) . - ':</strong> ' . - '<input type="text" name="' . - $name . - '[]" class="admin__control-text input-text input-text-range"' . - ' value="' . - $fromValue . - '"/> ' . - '<strong class="admin__control-support-text">' . - __( - 'To' - ) . - ':</strong> <input type="text" name="' . - $name . - '[]" class="admin__control-text input-text input-text-range" value="' . - $toValue . - '" />'; + return '<strong class="admin__control-support-text">' . + $this->getFromAttributePrefix($attribute) . + ':</strong> ' . + '<input type="text" name="' . + $name . + '[]" class="admin__control-text input-text input-text-range"' . + ' value="' . + $fromValue . + '"/> ' . + '<strong class="admin__control-support-text">' . + __( + 'To' + ) . + ':</strong> <input type="text" name="' . + $name . + '[]" class="admin__control-text input-text input-text-range" value="' . + $toValue . + '" />'; + } + + /** + * Get 'From' prefix to attribute. + * + * @param Attribute $attribute + * @return \Magento\Framework\Phrase + */ + protected function getFromAttributePrefix(Attribute $attribute) + { + $attributePrefix = $attribute->getAttributeCode() === ProductAttributeInterface::CODE_TIER_PRICE + ? __('Fixed Price: From') + : __('From'); + + return $attributePrefix; } /** diff --git a/app/code/Magento/ImportExport/Files/Sample/advanced_pricing.csv b/app/code/Magento/ImportExport/Files/Sample/advanced_pricing.csv index 82db6382bd8d5fda511e50a6da9fa4876fa35f1a..e4c203bed3be9ae6f935e7cb1f6cfbeb086d8816 100644 --- a/app/code/Magento/ImportExport/Files/Sample/advanced_pricing.csv +++ b/app/code/Magento/ImportExport/Files/Sample/advanced_pricing.csv @@ -1,5 +1,5 @@ -sku,tier_price_website,tier_price_customer_group,tier_price_qty,tier_price -sku123,base,General,2,10 -sku124,All Websites [USD],ALL GROUPS,3,15 -sku123,,,, -sku124,,,, +sku,tier_price_website,tier_price_customer_group,tier_price_qty,tier_price,tier_price_value_type +sku123,base,General,2,10,Fixed +sku124,All Websites [USD],ALL GROUPS,3,15,Discount +sku123,,,,, +sku124,,,,, diff --git a/app/code/Magento/ImportExport/composer.json b/app/code/Magento/ImportExport/composer.json index 5e403d2180652a6f3565bf03b573abf75310f19f..d5e3b41f47fd93387b0ce70e1764105fa7341027 100644 --- a/app/code/Magento/ImportExport/composer.json +++ b/app/code/Magento/ImportExport/composer.json @@ -3,6 +3,7 @@ "description": "N/A", "require": { "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", + "magento/module-catalog": "101.1.*", "magento/module-store": "100.2.*", "magento/module-backend": "100.2.*", "magento/module-eav": "100.2.*", diff --git a/app/code/Magento/Multishipping/Block/Checkout/Billing/Items.php b/app/code/Magento/Multishipping/Block/Checkout/Billing/Items.php index 5a3e581d5375bb983baac8516b63788331388da9..3d2ca91d3ba6c0b687a6361858ce13269967861e 100644 --- a/app/code/Magento/Multishipping/Block/Checkout/Billing/Items.php +++ b/app/code/Magento/Multishipping/Block/Checkout/Billing/Items.php @@ -68,7 +68,7 @@ class Items extends \Magento\Sales\Block\Items\AbstractItems */ public function getVirtualProductEditUrl() { - return $this->getUrl('*/cart'); + return $this->getUrl('checkout/cart'); } /** diff --git a/app/code/Magento/Multishipping/Block/Checkout/Overview.php b/app/code/Magento/Multishipping/Block/Checkout/Overview.php index 0031b6416d333eb32eb032ead7267ca4d8f9da9c..299e85d6f13c31a4633d9886f4565866def62802 100644 --- a/app/code/Magento/Multishipping/Block/Checkout/Overview.php +++ b/app/code/Magento/Multishipping/Block/Checkout/Overview.php @@ -297,7 +297,7 @@ class Overview extends \Magento\Sales\Block\Items\AbstractItems */ public function getVirtualProductEditUrl() { - return $this->getUrl('*/cart'); + return $this->getUrl('checkout/cart'); } /** diff --git a/app/code/Magento/Multishipping/Test/Unit/Block/Checkout/Billing/ItemsTest.php b/app/code/Magento/Multishipping/Test/Unit/Block/Checkout/Billing/ItemsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..056ac173621743ac162ba744d83a60d097cf12fc --- /dev/null +++ b/app/code/Magento/Multishipping/Test/Unit/Block/Checkout/Billing/ItemsTest.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Multishipping\Test\Unit\Block\Checkout\Billing; + + +class ItemsTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Multishipping\Block\Checkout\Billing\Items + */ + private $model; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $urlBuilderMock; + + protected function setUp() + { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->urlBuilderMock = $this->getMock(\Magento\Framework\UrlInterface::class); + $this->model = $objectManager->getObject( + \Magento\Multishipping\Block\Checkout\Billing\Items::class, + [ + 'urlBuilder' => $this->urlBuilderMock + ] + ); + } + + public function testGetVirtualProductEditUrl() + { + $url = 'http://example.com'; + $this->urlBuilderMock->expects($this->once())->method('getUrl')->with('checkout/cart', [])->willReturn($url); + $this->assertEquals($url, $this->model->getVirtualProductEditUrl()); + } +} diff --git a/app/code/Magento/Multishipping/Test/Unit/Block/Checkout/OverviewTest.php b/app/code/Magento/Multishipping/Test/Unit/Block/Checkout/OverviewTest.php index fc2169f38e4af88559b112931ac0952ecd82f5d0..b583ad258595b7101fb8683df6c9932a20ee1b3f 100644 --- a/app/code/Magento/Multishipping/Test/Unit/Block/Checkout/OverviewTest.php +++ b/app/code/Magento/Multishipping/Test/Unit/Block/Checkout/OverviewTest.php @@ -52,6 +52,11 @@ class OverviewTest extends \PHPUnit_Framework_TestCase */ protected $quoteMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $urlBuilderMock; + protected function setUp() { $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -83,13 +88,15 @@ class OverviewTest extends \PHPUnit_Framework_TestCase $this->checkoutMock = $this->getMock(\Magento\Multishipping\Model\Checkout\Type\Multishipping::class, [], [], '', false); $this->quoteMock = $this->getMock(\Magento\Quote\Model\Quote::class, [], [], '', false); + $this->urlBuilderMock = $this->getMock(\Magento\Framework\UrlInterface::class); $this->model = $objectManager->getObject( \Magento\Multishipping\Block\Checkout\Overview::class, [ 'priceCurrency' => $this->priceCurrencyMock, 'totalsCollector' => $this->totalsCollectorMock, 'totalsReader' => $this->totalsReaderMock, - 'multishipping' => $this->checkoutMock + 'multishipping' => $this->checkoutMock, + 'urlBuilder' => $this->urlBuilderMock ] ); } @@ -189,4 +196,11 @@ class OverviewTest extends \PHPUnit_Framework_TestCase ->willReturn([$totalMock]); return $totalMock; } + + public function testGetVirtualProductEditUrl() + { + $url = 'http://example.com'; + $this->urlBuilderMock->expects($this->once())->method('getUrl')->with('checkout/cart', [])->willReturn($url); + $this->assertEquals($url, $this->model->getVirtualProductEditUrl()); + } } diff --git a/app/code/Magento/Payment/Plugin/PaymentConfigurationProcess.php b/app/code/Magento/Payment/Plugin/PaymentConfigurationProcess.php new file mode 100644 index 0000000000000000000000000000000000000000..5b107b74295b3a842c00429543b00e0466b1d530 --- /dev/null +++ b/app/code/Magento/Payment/Plugin/PaymentConfigurationProcess.php @@ -0,0 +1,73 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Payment\Plugin; + +/** + * Class PaymentConfigurationProcess + * + * Removes inactive payment methods and group from checkout configuration. + */ +class PaymentConfigurationProcess +{ + /** + * @var \Magento\Payment\Api\PaymentMethodListInterface + */ + private $paymentMethodList; + + /** + * @var \Magento\Store\Model\StoreManagerInterface + */ + private $storeManager; + + /** + * @param \Magento\Payment\Api\PaymentMethodListInterface $paymentMethodList + * @param \Magento\Store\Model\StoreManagerInterface $storeManager + */ + public function __construct( + \Magento\Payment\Api\PaymentMethodListInterface $paymentMethodList, + \Magento\Store\Model\StoreManagerInterface $storeManager + ) { + $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); + $getCodeFunc = function ($method) { + return $method->getCode(); + }; + $activePaymentMethodCodes = array_map($getCodeFunc, $activePaymentMethodList); + + foreach ($configuration as $paymentGroup => $groupConfig) { + $notActivePaymentMethodCodes = array_diff(array_keys($groupConfig['methods']), $activePaymentMethodCodes); + foreach ($notActivePaymentMethodCodes as $notActivePaymentMethodCode) { + unset($configuration[$paymentGroup]['methods'][$notActivePaymentMethodCode]); + } + if (empty($configuration[$paymentGroup]['methods'])) { + unset($configuration[$paymentGroup]); + } + } + + return [$jsLayout]; + } +} diff --git a/app/code/Magento/Payment/Test/Unit/Plugin/PaymentConfigurationProcessTest.php b/app/code/Magento/Payment/Test/Unit/Plugin/PaymentConfigurationProcessTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3e49c8718e6044de36cc6a1018d052dc48ed7485 --- /dev/null +++ b/app/code/Magento/Payment/Test/Unit/Plugin/PaymentConfigurationProcessTest.php @@ -0,0 +1,146 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Payment\Test\Unit\Plugin; + +/** + * Class PaymentConfigurationProcessTest. + */ +class PaymentConfigurationProcessTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $storeManager; + + /** + * @var \Magento\Store\Api\Data\StoreInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $store; + + /** + * @var \Magento\Payment\Api\PaymentMethodListInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $paymentMethodList; + + /** + * @var \Magento\Checkout\Block\Checkout\LayoutProcessor|\PHPUnit_Framework_MockObject_MockObject + */ + private $layoutProcessor; + + /** + * @var \Magento\Payment\Plugin\PaymentConfigurationProcess + */ + private $plugin; + + /** + * Set up + */ + protected function setUp() + { + $this->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->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\Payment\Plugin\PaymentConfigurationProcess::class, + [ + 'paymentMethodList' => $this->paymentMethodList, + 'storeManager' => $this->storeManager + ] + ); + } + + /** + * @param array $jsLayout + * @param array $activePaymentList + * @param array $expectedResult + * @dataProvider beforeProcessDataProvider + */ + public function testBeforeProcess($jsLayout, $activePaymentList, $expectedResult) + { + $this->store->expects($this->once())->method('getId')->willReturn(1); + $this->storeManager->expects($this->once())->method('getStore')->willReturn($this->store); + $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'] = [ + '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'] = [ + 'braintree' => [ + 'methods' => [ + 'braintree' => [], + 'braintree_paypal' => [] + ] + ] + ]; + + $braintreePaymentMethod = $this + ->getMockBuilder(\Magento\Payment\Api\Data\PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getCode']) + ->getMockForAbstractClass(); + $braintreePaypalPaymentMethod = $this + ->getMockBuilder(\Magento\Payment\Api\Data\PaymentMethodInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getCode']) + ->getMockForAbstractClass(); + + $braintreePaymentMethod->expects($this->any())->method('getCode')->willReturn('braintree'); + $braintreePaypalPaymentMethod->expects($this->any())->method('getCode')->willReturn('braintree_paypal'); + + return [ + [$jsLayout, [], $result1], + [$jsLayout, [$braintreePaymentMethod, $braintreePaypalPaymentMethod], $result2] + ]; + } +} diff --git a/app/code/Magento/Payment/etc/frontend/di.xml b/app/code/Magento/Payment/etc/frontend/di.xml index 4ff3c013b676523fe20a3deb49f32758c01e604e..471a7ce9e2de585609eb490ada35248c4ee59be3 100644 --- a/app/code/Magento/Payment/etc/frontend/di.xml +++ b/app/code/Magento/Payment/etc/frontend/di.xml @@ -19,4 +19,7 @@ </argument> </arguments> </type> + <type name="Magento\Checkout\Block\Checkout\LayoutProcessor"> + <plugin name="ProcessPaymentConfiguration" type="Magento\Payment\Plugin\PaymentConfigurationProcess"/> + </type> </config> \ No newline at end of file diff --git a/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail.php b/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail.php index 70eb41e8fcbdf6f8b55c00a8bd291a2ceef68df1..e97a1a2f9d64c9d60c82869ed2ff882dcecd5979 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail.php @@ -131,7 +131,7 @@ class Detail extends \Magento\Backend\Block\Widget\Container $this->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/view/adminhtml/ui_component/sales_order_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml index e0a5471b1e45ee1f6ba9bd8c05d0145656a642ea..0dc555c93d94d3db64e102f24b2fa4e6f45e278f 100644 --- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml @@ -322,7 +322,7 @@ </item> </argument> </column> - <column name="total_refunded" class="Magento\Sales\Ui\Component\Listing\Column\Price"> + <column name="total_refunded" class="Magento\Sales\Ui\Component\Listing\Column\PurchasedPrice"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="filter" xsi:type="string">textRange</item> diff --git a/app/code/Magento/Tax/Model/Sales/Total/Quote/CommonTaxCollector.php b/app/code/Magento/Tax/Model/Sales/Total/Quote/CommonTaxCollector.php index 07b9c558043b0ddee1c3b99f63fa0b2f8aa27490..c2c53a3d7754ab080bb9fa818d3cb8d65eac2531 100644 --- a/app/code/Magento/Tax/Model/Sales/Total/Quote/CommonTaxCollector.php +++ b/app/code/Magento/Tax/Model/Sales/Total/Quote/CommonTaxCollector.php @@ -535,6 +535,7 @@ class CommonTaxCollector extends AbstractTotal $total->setSubtotalInclTax($subtotalInclTax); $total->setBaseSubtotalTotalInclTax($baseSubtotalInclTax); $total->setBaseSubtotalInclTax($baseSubtotalInclTax); + $shippingAssignment->getShipping()->getAddress()->setBaseSubtotalTotalInclTax($baseSubtotalInclTax);; return $this; } diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/select.js b/app/code/Magento/Ui/view/base/web/js/form/element/select.js index 1887639c8d0313fe466aadb89b3cdaf7adc6bd81..4567bba1d017aec81e53dc668b35b4bf696c49d3 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/select.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/select.js @@ -105,7 +105,9 @@ define([ return Abstract.extend({ defaults: { customName: '${ $.parentName }.${ $.index }_input', - elementTmpl: 'ui/form/element/select' + elementTmpl: 'ui/form/element/select', + caption: '', + options: [] }, /** @@ -127,28 +129,6 @@ define([ return this; }, - /** - * Parses options and merges the result with instance - * - * @param {Object} config - * @returns {Object} Chainable. - */ - initConfig: function (config) { - var options = config.options, - captionValue = config.captionValue || '', - result = parseOptions(options, captionValue); - - if (config.caption) { - delete result.caption; - } - - _.extend(config, result); - - this._super(); - - return this; - }, - /** * Calls 'initObservable' of parent, initializes 'options' and 'initialOptions' * properties, calls 'setOptions' passing options to it @@ -160,7 +140,7 @@ define([ this.initialOptions = this.options; - this.observe('options') + this.observe('options caption') .setOptions(this.options()); return this; @@ -209,7 +189,7 @@ define([ return option && option.value; } - if (!this.caption) { + if (!this.caption()) { return findFirst(this.options); } }, @@ -254,14 +234,20 @@ define([ * @returns {Object} Chainable */ setOptions: function (data) { - var isVisible; + var captionValue = this.captionValue || '', + result = parseOptions(data, captionValue), + isVisible; + + this.indexedOptions = indexOptions(result.options); - this.indexedOptions = indexOptions(data); + this.options(result.options); - this.options(data); + if (!this.caption()) { + this.caption(result.caption); + } if (this.customEntry) { - isVisible = !!data.length; + isVisible = !!result.options.length; this.setVisible(isVisible); this.toggleInput(!isVisible); @@ -301,7 +287,7 @@ define([ * @returns {Object} Chainable. */ clear: function () { - var value = this.caption ? '' : findFirst(this.options); + var value = this.caption() ? '' : findFirst(this.options); this.value(value); diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js index 01c8ef29029a9ef34f82885e3efbada75774a88b..209b05773a497b8e02d36cdd4adba10eab107779 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js @@ -93,7 +93,7 @@ define([ /* eslint-disable no-undef */ if (tinyMCE) { _.each(tinyMCE.activeEditor.controlManager.controls, function (property, index, controls) { - controls[property].setDisabled(status); + controls[property.id].setDisabled(status); }); tinyMCE.activeEditor.getBody().setAttribute('contenteditable', !status); diff --git a/app/code/Magento/Vault/Plugin/PaymentVaultConfigurationProcess.php b/app/code/Magento/Vault/Plugin/PaymentVaultConfigurationProcess.php new file mode 100644 index 0000000000000000000000000000000000000000..db38ccbed417a95870a9da916a64e36b4281353d --- /dev/null +++ b/app/code/Magento/Vault/Plugin/PaymentVaultConfigurationProcess.php @@ -0,0 +1,93 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Vault\Plugin; + +/** + * Class PaymentVaultConfigurationProcess + * + * Checks if vault group have active vaults. + */ +class PaymentVaultConfigurationProcess +{ + /** + * @var \Magento\Vault\Api\PaymentMethodListInterface + */ + private $vaultPaymentList; + + /** + * @var \Magento\Vault\Api\PaymentMethodListInterface + */ + private $paymentMethodList; + + /** + * @var \Magento\Store\Model\StoreManagerInterface + */ + private $storeManager; + + /** + * @param \Magento\Vault\Api\PaymentMethodListInterface $vaultPaymentList + * @param \Magento\Payment\Api\PaymentMethodListInterface $paymentMethodList + * @param \Magento\Store\Model\StoreManagerInterface $storeManager + */ + public function __construct( + \Magento\Vault\Api\PaymentMethodListInterface $vaultPaymentList, + \Magento\Payment\Api\PaymentMethodListInterface $paymentMethodList, + \Magento\Store\Model\StoreManagerInterface $storeManager + ) { + $this->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/Test/Unit/Plugin/PaymentVaultConfigurationProcessTest.php b/app/code/Magento/Vault/Test/Unit/Plugin/PaymentVaultConfigurationProcessTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7e7a3fd0aebdfcd8054a7276dcce04ec5f49dcb8 --- /dev/null +++ b/app/code/Magento/Vault/Test/Unit/Plugin/PaymentVaultConfigurationProcessTest.php @@ -0,0 +1,158 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Vault\Test\Unit\Plugin; + +/** + * Class PaymentVaultConfigurationProcessTest. + */ +class PaymentVaultConfigurationProcessTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $storeManager; + + /** + * @var \Magento\Store\Api\Data\StoreInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $store; + + /** + * @var \Magento\Vault\Api\PaymentMethodListInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $vaultList; + + /** + * @var \Magento\Payment\Api\PaymentMethodListInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $paymentMethodList; + + /** + * @var \Magento\Checkout\Block\Checkout\LayoutProcessor|\PHPUnit_Framework_MockObject_MockObject + */ + private $layoutProcessor; + + /** + * @var \Magento\Vault\Plugin\PaymentVaultConfigurationProcess + */ + private $plugin; + + /** + * Set up + */ + protected function setUp() + { + $this->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/etc/frontend/di.xml b/app/code/Magento/Vault/etc/frontend/di.xml index d7f699faff53c6e48c6d3d854b265ded269e4dcc..0af0e4cd32217f952d3c49fc7424e99bc8a1ffe0 100644 --- a/app/code/Magento/Vault/etc/frontend/di.xml +++ b/app/code/Magento/Vault/etc/frontend/di.xml @@ -19,4 +19,8 @@ <argument name="session" xsi:type="object">Magento\Customer\Model\Session</argument> </arguments> </type> + <type name="Magento\Checkout\Block\Checkout\LayoutProcessor"> + <plugin name="ProcessPaymentVaultConfiguration" type="Magento\Vault\Plugin\PaymentVaultConfigurationProcess"/> + <plugin name="ProcessPaymentConfiguration" disabled="true"/> + </type> </config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml index dff1a9fd71d865dd52fd6cdd0e05d3e3d000db94..411833f03335645e4395cd8bb5695121cc4c2dad 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml @@ -90,6 +90,10 @@ <input>input</input> <selector>input[name='url_key']</selector> </url_key> + <use_default_url_key> + <input>checkbox</input> + <selector>input[name='use_default[url_key]']</selector> + </use_default_url_key> <meta_title> <input>input</input> <selector>input[name='meta_title']</selector> 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 27e15044df11d91765251d1de783243cf6b55adf..808da58c7dd4995a20f88ef2059df2ecc9eb574f 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 @@ -7,12 +7,18 @@ namespace Magento\Catalog\Test\Block\Adminhtml\Category\Edit; use Magento\Backend\Test\Block\FormPageActions; +use Magento\Mtf\Client\Locator; /** * Category page actions. */ class PageActions extends FormPageActions { + /** + * Top page element to implement a scrolling in case of floating blocks overlay. + */ + const TOP_ELEMENT_TO_SCROLL = '.page-title'; + /** * Locator for "OK" button in warning block * @@ -20,6 +26,20 @@ class PageActions extends FormPageActions */ protected $warningBlock = '.ui-widget-content .ui-dialog-buttonset button:first-child'; + /** + * Change Store View selector. + * + * @var string + */ + protected $storeChangeButton = '#store-change-button'; + + /** + * Selector for confirm. + * + * @var string + */ + protected $confirmModal = '.confirm._show[data-role=modal]'; + /** * Click on "Save" button * @@ -33,4 +53,23 @@ class PageActions extends FormPageActions $warningBlock->click(); } } + + /** + * Select Store View. + * + * @param string $name + * @return void + */ + public function selectStoreView($name) + { + $this->browser->find(self::TOP_ELEMENT_TO_SCROLL)->click(); + $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/Tree.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Tree.php index 15a624c4b734f828264ebfee75801d80d08c5f05..447e1319898084dfecbcb50e3f801ae04ae9f156 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Tree.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Tree.php @@ -60,6 +60,13 @@ class Tree extends Block */ protected $header = 'header'; + /** + * Xpath locator for category in tree. + * + * @var string + */ + protected $categoryInTree = '//*[@class="x-tree-node-ct"]/li/div/a/span[contains(text(), "%s")]/..'; + /** * Get backend abstract block. * @@ -153,6 +160,26 @@ class Tree extends Block ->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 + ); + $this->_rootElement->find(sprintf($this->categoryInTree, $childCategoryName), Locator::SELECTOR_XPATH) + ->dragAndDrop($targetElement); + } + /** * Expand all categories tree. * diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing/OptionTier.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing/OptionTier.xml index ca10de4ebf8c127fdb310073437261cab7d7a435..9df266994f4fad767a0c13478bdc2e8cbb002c99 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing/OptionTier.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing/OptionTier.xml @@ -10,6 +10,13 @@ <price> <selector>[name$="[price]"]</selector> </price> + <value_type> + <selector>[name$="[value_type]"]</selector> + <input>select</input> + </value_type> + <percentage_value> + <selector>[name$="[percentage_value]"]</selector> + </percentage_value> <website> <selector>[name$="[website_id]"]</selector> <input>select</input> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php index b6e95f5393e1455796b190642414d0e53345b59c..08d38f45c4ff99a4eae99a1be3c3972bdba7f790 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php @@ -14,9 +14,12 @@ use Magento\Mtf\Client\Element\SimpleElement; use Magento\Mtf\Client\Locator; use Magento\Mtf\Fixture\FixtureInterface; use Magento\Ui\Test\Block\Adminhtml\DataGrid; +use Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\ProductDetails\NewCategoryIds; /** * Product form on backend product page. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ProductForm extends FormSections { @@ -48,6 +51,13 @@ class ProductForm extends FormSections */ protected $attributeBlock = '[data-index="%s"]'; + /** + * NewCategoryIds block selector. + * + * @var string + */ + protected $newCategoryModalForm = '.product_form_product_form_create_category_modal'; + /** * Magento form loader. * @@ -70,8 +80,6 @@ class ProductForm extends FormSections * @param FixtureInterface|null $category * @return $this * @throws \Exception - * - * @SuppressWarnings(PHPMD.NPathComplexity) */ public function fill(FixtureInterface $product, SimpleElement $element = null, FixtureInterface $category = null) { @@ -88,9 +96,14 @@ class ProductForm extends FormSections $this->callRender($typeId, 'fill', $renderArguments); } else { $sections = $this->getFixtureFieldsByContainers($product); - + $category = $product->hasData('category_ids') + ? $product->getDataFieldConfig('category_ids')['source']->getCategories()[0] : $category; if ($category) { - $sections['product-details']['category_ids']['value'] = $category->getName(); + if ((int)$category->getId()) { + $sections['product-details']['category_ids']['value'] = $category->getName(); + } else { + $this->getNewCategoryModalForm()->addNewCategory($category); + } } $this->fillContainers($sections, $element); } @@ -193,6 +206,19 @@ class ProductForm extends FormSections ); } + /** + * 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/Links/CompareLink.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Links/CompareLink.php index c81d85a724dcf22ef37e2aa497bf2c6be22f51bd..86c30f4caf8a4ccb10bd7cdebc5f5b8137bfa6b2 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Links/CompareLink.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Links/CompareLink.php @@ -20,6 +20,13 @@ class CompareLink extends Block */ protected $qtyCompareProducts = '.compare .counter.qty'; + /** + * Locator value for Compare Products link. + * + * @var string + */ + protected $linkCompareProducts = '[data-role="compare-products-link"] a.compare'; + /** * Get qty of Products in Compare list. * @@ -32,4 +39,14 @@ class CompareLink extends Block preg_match_all('/^\d+/', $compareProductLink->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/ProductList/TopToolbar.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/TopToolbar.php index 3d5e550560e857b8530037637b4f97f7763874e2..f7529f1fcb61e262856bdf8856c0cbaf14ce57d2 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/TopToolbar.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/TopToolbar.php @@ -36,12 +36,11 @@ class TopToolbar extends Block /** * Get all available method of sorting product * - * @return array|string + * @return array */ public function getSortType() { $content = $this->_rootElement->find($this->sorter)->getText(); - preg_match_all('/\w+\s?\w+/', $content, $matches); - return $matches[0]; + return explode("\n", $content); } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceInCart.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceInCart.php new file mode 100644 index 0000000000000000000000000000000000000000..1bc689d8e1b1e3009bbf2f3fc563b3aa51ccc3c7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceInCart.php @@ -0,0 +1,129 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Test\Constraint; + +use Magento\Catalog\Test\Fixture\CatalogProductSimple; +use Magento\Catalog\Test\Page\Product\CatalogProductView; +use Magento\Checkout\Test\Page\CheckoutCart; +use Magento\Mtf\Client\BrowserInterface; +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Mtf\Fixture\FixtureInterface; + +/** + * This assert adds product to cart and checks price. + */ +class AssertProductTierPriceInCart extends AbstractConstraint +{ + /** + * Price on form. + * + * @var string + */ + private $formPrice; + + /** + * Fixture actual price. + * + * @var string + */ + private $fixtureActualPrice; + + /** + * Fixture price. + * + * @var string + */ + private $fixturePrice; + + /** + * Assertion that the product is correctly displayed in cart. + * + * @param CatalogProductView $catalogProductView + * @param FixtureInterface $product + * @param BrowserInterface $browser + * @param CheckoutCart $checkoutCart + * @return void + */ + public function processAssert( + CatalogProductView $catalogProductView, + FixtureInterface $product, + BrowserInterface $browser, + CheckoutCart $checkoutCart + ) { + $checkoutCart->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'] === "Percent") { + $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/Fixture/Category.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml index b9ba495535e82eb970f8ff02ebaa7097aab999b0..ed6f9568c2441aa1bba72eb3992cb6b6f89066f7 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 @@ -41,6 +41,7 @@ <field name="use_config_price_range" is_required="0" group="display_setting" /> <field name="layered_navigation_price_step" is_required="0" group="display_setting" /> <field name="url_key" group="seo" /> + <field name="use_default_url_key" group="seo" /> <field name="meta_title" is_required="" group="seo" /> <field name="meta_keywords" is_required="" group="seo" /> <field name="meta_description" is_required="" group="seo" /> 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 e1cbc1a1d8ba2dba7f3be971b3f1b456f6e7d02a..997d0ab1d7f11c64ce33ea386870055ea2e77798 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 @@ -98,6 +98,87 @@ <field name="url_key" xsi:type="string">simple-product-%isolation%</field> </dataset> + <dataset name="product_1_dollar"> + <field name="attribute_set_id" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </field> + <field name="name" xsi:type="string">product_1_dollar %isolation%</field> + <field name="sku" xsi:type="string">sku_product_1_dollar_%isolation%</field> + <field name="product_has_weight" xsi:type="string">This item has weight</field> + <field name="weight" xsi:type="string">1</field> + <field name="quantity_and_stock_status" xsi:type="array"> + <item name="qty" xsi:type="string">1000</item> + <item name="is_in_stock" xsi:type="string">In Stock</item> + </field> + <field name="price" xsi:type="array"> + <item name="value" xsi:type="string">1</item> + </field> + <field name="tax_class_id" xsi:type="array"> + <item name="dataset" xsi:type="string">taxable_goods</item> + </field> + <field name="website_ids" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </item> + </field> + <field name="visibility" xsi:type="string">Catalog, Search</field> + <field name="url_key" xsi:type="string">product-1-dollar-%isolation%</field> + </dataset> + + <dataset name="product_5_dollar"> + <field name="attribute_set_id" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </field> + <field name="name" xsi:type="string">product_5_dollar %isolation%</field> + <field name="sku" xsi:type="string">sku_product_5_dollar_%isolation%</field> + <field name="product_has_weight" xsi:type="string">This item has weight</field> + <field name="weight" xsi:type="string">1</field> + <field name="quantity_and_stock_status" xsi:type="array"> + <item name="qty" xsi:type="string">1000</item> + <item name="is_in_stock" xsi:type="string">In Stock</item> + </field> + <field name="price" xsi:type="array"> + <item name="value" xsi:type="string">5</item> + </field> + <field name="tax_class_id" xsi:type="array"> + <item name="dataset" xsi:type="string">taxable_goods</item> + </field> + <field name="website_ids" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </item> + </field> + <field name="visibility" xsi:type="string">Catalog, Search</field> + <field name="url_key" xsi:type="string">product-5-dollar-%isolation%</field> + </dataset> + + <dataset name="product_9_99_dollar"> + <field name="attribute_set_id" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </field> + <field name="name" xsi:type="string">product_9_99_dollar %isolation%</field> + <field name="sku" xsi:type="string">sku_product_9_99_dollar_%isolation%</field> + <field name="product_has_weight" xsi:type="string">This item has weight</field> + <field name="weight" xsi:type="string">1</field> + <field name="quantity_and_stock_status" xsi:type="array"> + <item name="qty" xsi:type="string">1000</item> + <item name="is_in_stock" xsi:type="string">In Stock</item> + </field> + <field name="price" xsi:type="array"> + <item name="value" xsi:type="string">9.99</item> + </field> + <field name="tax_class_id" xsi:type="array"> + <item name="dataset" xsi:type="string">taxable_goods</item> + </field> + <field name="website_ids" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </item> + </field> + <field name="visibility" xsi:type="string">Catalog, Search</field> + <field name="url_key" xsi:type="string">product-9-99-dollar-%isolation%</field> + </dataset> + <dataset name="product_10_dollar"> <field name="attribute_set_id" xsi:type="array"> <item name="dataset" xsi:type="string">default</item> @@ -128,6 +209,33 @@ </field> </dataset> + <dataset name="product_15_dollar"> + <field name="attribute_set_id" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </field> + <field name="name" xsi:type="string">product_15_dollar %isolation%</field> + <field name="sku" xsi:type="string">sku_product_15_dollar_%isolation%</field> + <field name="product_has_weight" xsi:type="string">This item has weight</field> + <field name="weight" xsi:type="string">1</field> + <field name="quantity_and_stock_status" xsi:type="array"> + <item name="qty" xsi:type="string">1000</item> + <item name="is_in_stock" xsi:type="string">In Stock</item> + </field> + <field name="price" xsi:type="array"> + <item name="value" xsi:type="string">15</item> + </field> + <field name="tax_class_id" xsi:type="array"> + <item name="dataset" xsi:type="string">taxable_goods</item> + </field> + <field name="website_ids" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </item> + </field> + <field name="visibility" xsi:type="string">Catalog, Search</field> + <field name="url_key" xsi:type="string">product-15-dollar-%isolation%</field> + </dataset> + <dataset name="product_20_dollar"> <field name="attribute_set_id" xsi:type="array"> <item name="dataset" xsi:type="string">default</item> @@ -155,6 +263,33 @@ <field name="url_key" xsi:type="string">product-20-dollar-%isolation%</field> </dataset> + <dataset name="product_21_dollar"> + <field name="attribute_set_id" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </field> + <field name="name" xsi:type="string">product_21_dollar %isolation%</field> + <field name="sku" xsi:type="string">sku_product_21_dollar_%isolation%</field> + <field name="product_has_weight" xsi:type="string">This item has weight</field> + <field name="weight" xsi:type="string">1</field> + <field name="quantity_and_stock_status" xsi:type="array"> + <item name="qty" xsi:type="string">1000</item> + <item name="is_in_stock" xsi:type="string">In Stock</item> + </field> + <field name="price" xsi:type="array"> + <item name="value" xsi:type="string">21</item> + </field> + <field name="tax_class_id" xsi:type="array"> + <item name="dataset" xsi:type="string">taxable_goods</item> + </field> + <field name="website_ids" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </item> + </field> + <field name="visibility" xsi:type="string">Catalog, Search</field> + <field name="url_key" xsi:type="string">product-21-dollar-%isolation%</field> + </dataset> + <dataset name="product_with_url_key"> <field name="name" xsi:type="string">Simple Product %isolation%</field> <field name="sku" xsi:type="string">sku_simple_product_%isolation%</field> @@ -1263,5 +1398,101 @@ </field> </dataset> + <dataset name="with_default_custom_option"> + <field name="attribute_set_id" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </field> + <field name="name" xsi:type="string">Simple Product %isolation%</field> + <field name="sku" xsi:type="string">sku_simple_product_%isolation%</field> + <field name="price" xsi:type="array"> + <item name="value" xsi:type="string">56.78</item> + </field> + <field name="product_has_weight" xsi:type="string">This item has weight</field> + <field name="weight" xsi:type="string">1</field> + <field name="quantity_and_stock_status" xsi:type="array"> + <item name="qty" xsi:type="string">1</item> + <item name="is_in_stock" xsi:type="string">In Stock</item> + </field> + <field name="website_ids" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </item> + </field> + <field name="url_key" xsi:type="string">simple-product-%isolation%</field> + <field name="category_ids" xsi:type="array"> + <item name="dataset" xsi:type="string">default_subcategory</item> + </field> + <field name="custom_options" xsi:type="array"> + <item name="dataset" xsi:type="string">percent_and_fixed_radio_options</item> + </field> + <field name="checkout_data" xsi:type="array"> + <item name="dataset" xsi:type="string">simple_order_qty_1_price_56</item> + </field> + </dataset> + + <dataset name="with_fixed_custom_option"> + <field name="attribute_set_id" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </field> + <field name="name" xsi:type="string">Simple Product %isolation%</field> + <field name="sku" xsi:type="string">sku_simple_product_%isolation%</field> + <field name="price" xsi:type="array"> + <item name="value" xsi:type="string">56.78</item> + </field> + <field name="product_has_weight" xsi:type="string">This item has weight</field> + <field name="weight" xsi:type="string">1</field> + <field name="quantity_and_stock_status" xsi:type="array"> + <item name="qty" xsi:type="string">1</item> + <item name="is_in_stock" xsi:type="string">In Stock</item> + </field> + <field name="website_ids" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </item> + </field> + <field name="url_key" xsi:type="string">simple-product-%isolation%</field> + <field name="category_ids" xsi:type="array"> + <item name="dataset" xsi:type="string">default_subcategory</item> + </field> + <field name="custom_options" xsi:type="array"> + <item name="dataset" xsi:type="string">percent_and_fixed_radio_options</item> + </field> + <field name="checkout_data" xsi:type="array"> + <item name="dataset" xsi:type="string">with_fixed_custom_option</item> + </field> + </dataset> + + <dataset name="with_percent_custom_option"> + <field name="attribute_set_id" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </field> + <field name="name" xsi:type="string">Simple Product %isolation%</field> + <field name="sku" xsi:type="string">sku_simple_product_%isolation%</field> + <field name="price" xsi:type="array"> + <item name="value" xsi:type="string">56.78</item> + </field> + <field name="product_has_weight" xsi:type="string">This item has weight</field> + <field name="weight" xsi:type="string">1</field> + <field name="quantity_and_stock_status" xsi:type="array"> + <item name="qty" xsi:type="string">1</item> + <item name="is_in_stock" xsi:type="string">In Stock</item> + </field> + <field name="website_ids" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="dataset" xsi:type="string">default</item> + </item> + </field> + <field name="url_key" xsi:type="string">simple-product-%isolation%</field> + <field name="category_ids" xsi:type="array"> + <item name="dataset" xsi:type="string">default_subcategory</item> + </field> + <field name="custom_options" xsi:type="array"> + <item name="dataset" xsi:type="string">percent_and_fixed_radio_options</item> + </field> + <field name="checkout_data" xsi:type="array"> + <item name="dataset" xsi:type="string">with_percent_custom_option</item> + </field> + </dataset> + </repository> </config> 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 53ec00f56b1e87662966c8298fa4104a6f804b0e..180da27ca2a099ab36c00473ac35572c45a31ffd 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 @@ -101,6 +101,14 @@ </field> </dataset> + <dataset name="simple_order_qty_2"> + <field name="qty" xsi:type="string">2</field> + <field name="cartItem" xsi:type="array"> + <item name="price" xsi:type="string">560</item> + <item name="subtotal" xsi:type="string">560</item> + </field> + </dataset> + <dataset name="simple_two_products"> <field name="qty" xsi:type="string">2</field> <field name="cartItem" xsi:type="array"> @@ -148,5 +156,47 @@ <dataset name="simple_order_qty_3"> <field name="qty" xsi:type="string">3</field> </dataset> + + <dataset name="simple_order_qty_1_price_56"> + <field name="qty" xsi:type="string">1</field> + <field name="cartItem" xsi:type="array"> + <item name="price" xsi:type="string">49.40</item> + <item name="subtotal" xsi:type="string">49.40</item> + </field> + </dataset> + + <dataset name="with_fixed_custom_option"> + <field name="options" xsi:type="array"> + <item name="custom_options" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">attribute_key_0</item> + <item name="value" xsi:type="string">option_key_0</item> + </item> + </item> + </field> + <field name="qty" xsi:type="string">1</field> + <field name="cartItem" xsi:type="array"> + <item name="price" xsi:type="string">61.74</item> + <item name="qty" xsi:type="string">1</item> + <item name="subtotal" xsi:type="string">61.74</item> + </field> + </dataset> + + <dataset name="with_percent_custom_option"> + <field name="options" xsi:type="array"> + <item name="custom_options" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">attribute_key_0</item> + <item name="value" xsi:type="string">option_key_1</item> + </item> + </item> + </field> + <field name="qty" xsi:type="string">1</field> + <field name="cartItem" xsi:type="array"> + <item name="price" xsi:type="string">53.85</item> + <item name="qty" xsi:type="string">1</item> + <item name="subtotal" xsi:type="string">53.85</item> + </field> + </dataset> </repository> </config> 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 3252f0178e24195e724b45a17021d0528990070a..b977e23166f45ec9c471ea08c5e7dc7516a728c0 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 @@ -358,5 +358,46 @@ </item> </field> </dataset> + + <dataset name="percent_and_fixed_radio_options"> + <field name="0" xsi:type="array"> + <item name="title" xsi:type="string">custom menu</item> + <item name="is_require" xsi:type="string">No</item> + <item name="type" xsi:type="string">Select/Radio Buttons</item> + <item name="options" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">12.34 bucks</item> + <item name="price" xsi:type="string">12.34</item> + <item name="price_type" xsi:type="string">Fixed</item> + <item name="sku" xsi:type="string">sku_radio_buttons_row_1</item> + <item name="sort_order" xsi:type="string">0</item> + </item> + <item name="1" xsi:type="array"> + <item name="title" xsi:type="string">9 Percent</item> + <item name="price" xsi:type="string">9</item> + <item name="price_type" xsi:type="string">Percent</item> + <item name="sku" xsi:type="string">sku_radio_buttons_row_2</item> + <item name="sort_order" xsi:type="string">0</item> + </item> + </item> + </field> + </dataset> + + <dataset name="not_required_text_option"> + <field name="0" xsi:type="array"> + <item name="title" xsi:type="string">Test1 option %isolation%</item> + <item name="is_require" xsi:type="string">No</item> + <item name="type" xsi:type="string">Text/Field</item> + <item name="options" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="price" xsi:type="string">10</item> + <item name="price_type" xsi:type="string">Fixed</item> + <item name="sku" xsi:type="string">sku1_%isolation%</item> + <item name="max_characters" xsi:type="string">45</item> + </item> + </item> + </field> + </dataset> + </repository> </config> 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 412818cbe40e71634eb1e635d8dc8e1630913b49..2f517f4d6cf3cc03020abc575d4e91cd7f7188da 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 @@ -77,5 +77,29 @@ </item> </field> </dataset> + + <dataset name="custom_with_fixed_discount"> + <field name="0" xsi:type="array"> + <item name="value_type" xsi:type="string">Fixed</item> + <item name="price" xsi:type="string">95</item> + <item name="website" xsi:type="string">All Websites [USD]</item> + <item name="price_qty" xsi:type="string">5</item> + <item name="customer_group" xsi:type="array"> + <item name="dataset" xsi:type="string">ALL_GROUPS</item> + </item> + </field> + </dataset> + + <dataset name="custom_with_percentage_discount"> + <field name="0" xsi:type="array"> + <item name="value_type" xsi:type="string">Percent</item> + <item name="percentage_value" xsi:type="string">3</item> + <item name="website" xsi:type="string">All Websites [USD]</item> + <item name="price_qty" xsi:type="string">10</item> + <item name="customer_group" xsi:type="array"> + <item name="dataset" xsi:type="string">ALL_GROUPS</item> + </item> + </field> + </dataset> </repository> </config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml index fa81264dd2d4b061ef769f882408b104ba92793f..238fddba3de426f683e981c0a1b7b1b60c12fbeb 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml @@ -16,7 +16,7 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertCategoryForm" /> </variation> <variation name="CreateCategoryEntityTestVariation2_RootCategory_AllFields"> - <data name="tag" xsi:type="string">to_maintain:yes</data> + <data name="issue" xsi:type="string">MAGETWO-60635: [CE][Categories] Design update dates are incorrect after save</data> <data name="description" xsi:type="string">Create root category with all fields</data> <data name="addCategory" xsi:type="string">addRootCategory</data> <data name="category/data/is_active" xsi:type="string">Yes</data> @@ -57,7 +57,7 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertCategoryPage" /> </variation> <variation name="CreateCategoryEntityTestVariation4_Subcategory_AllFields"> - <data name="tag" xsi:type="string">to_maintain:yes</data> + <data name="issue" xsi:type="string">MAGETWO-60635: [CE][Categories] Design update dates are incorrect after save</data> <data name="description" xsi:type="string">Create not anchor subcategory specifying all fields</data> <data name="addCategory" xsi:type="string">addSubcategory</data> <data name="category/data/parent_id/dataset" xsi:type="string">default_category</data> @@ -86,13 +86,14 @@ <data name="category/data/apply_design_to_products" xsi:type="string">Yes</data> <data name="category/data/schedule_update_from" xsi:type="string">01/10/2014</data> <data name="category/data/schedule_update_to" xsi:type="string">12/31/2024</data> + <data name="filterByPath" xsi:type="string">request_path</data> <constraint name="Magento\Catalog\Test\Constraint\AssertCategorySaveMessage" /> + <constraint name="Magento\UrlRewrite\Test\Constraint\AssertUrlRewriteCategoryInGrid" /> <constraint name="Magento\Catalog\Test\Constraint\AssertCategoryForm" /> <constraint name="Magento\Catalog\Test\Constraint\AssertCategoryPage" /> <constraint name="Magento\Catalog\Test\Constraint\AssertCategoryForAssignedProducts" /> </variation> <variation name="CreateCategoryEntityTestVariation5_Anchor_MostOfFields"> - <data name="tag" xsi:type="string">to_maintain:yes</data> <data name="description" xsi:type="string">Create anchor subcategory with all fields</data> <data name="addCategory" xsi:type="string">addSubcategory</data> <data name="category/data/parent_id/dataset" xsi:type="string">default_category</data> @@ -153,7 +154,7 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertCategoryForAssignedProducts" /> </variation> <variation name="CreateCategoryEntityTestVariation9_ThreeNesting"> - <data name="tag" xsi:type="string">test_type:extended_acceptance_test, to_maintain:yes</data> + <data name="tag" xsi:type="string">test_type:extended_acceptance_test</data> <data name="description" xsi:type="string">Create category with three nesting</data> <data name="addCategory" xsi:type="string">addSubcategory</data> <data name="category/data/parent_id/dataset" xsi:type="string">two_nested_categories</data> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.xml index 9f4a5e4bb71fea9293612125157757f7e3d965da..7979faa5e1f761844fa5d1bb8bebd00430e87623 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.xml @@ -317,6 +317,7 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertProductTierPriceOnProductPage" /> </variation> <variation name="CreateSimpleProductEntityTestVariation18"> + <data name="issue" xsi:type="string">MAGETWO-60470: [Import Custom options] An error occurs on attempt to save the product with imported options</data> <data name="description" xsi:type="string">Create product wit suite of custom options</data> <data name="product/data/url_key" xsi:type="string">simple-product-%isolation%</data> <data name="product/data/name" xsi:type="string">Simple Product %isolation%</data> @@ -509,6 +510,24 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertProductPage" /> <constraint name="Magento\Catalog\Test\Constraint\AssertProductInCart" /> </variation> + <variation name="CreateSimpleProductEntityWithTierPriceTestVariation1" summary="Create Simple Product with fixed tier price."> + <data name="product/data/url_key" xsi:type="string">simple-product-%isolation%</data> + <data name="product/data/name" xsi:type="string">Simple Product %isolation%</data> + <data name="product/data/sku" xsi:type="string">simple_sku_%isolation%</data> + <data name="product/data/price/value" xsi:type="string">100.00</data> + <data name="product/data/quantity_and_stock_status/qty" xsi:type="string">555</data> + <data name="product/data/tier_price/dataset" xsi:type="string">custom_with_fixed_discount</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductTierPriceInCart" /> + </variation> + <variation name="CreateSimpleProductEntityWithTierPriceTestVariation2" summary="Create Simple Product with percentage tier price."> + <data name="product/data/url_key" xsi:type="string">simple-product-%isolation%</data> + <data name="product/data/name" xsi:type="string">Simple Product %isolation%</data> + <data name="product/data/sku" xsi:type="string">simple_sku_%isolation%</data> + <data name="product/data/price/value" xsi:type="string">200.00</data> + <data name="product/data/quantity_and_stock_status/qty" xsi:type="string">555</data> + <data name="product/data/tier_price/dataset" xsi:type="string">custom_with_percentage_discount</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductTierPriceInCart" /> + </variation> <variation name="CreateSimpleProductEntityWithImageTestVariation1" summary="Create product with image and try to save it again"> <data name="product/data/image/0/file" xsi:type="string">Magento/Catalog/Test/_files/test1.png</data> <data name="product/data/image/1/file" xsi:type="string">Magento/Catalog/Test/_files/test2.png</data> diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.php index 4a4c6a25321c8363133aa0d6696cb29a35c946b5..68972e5bb766d458425ad6bf0796760325b931e8 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.php @@ -11,6 +11,8 @@ use Magento\CatalogRule\Test\Fixture\CatalogRule; use Magento\Customer\Test\Fixture\Customer; use Magento\Mtf\Util\Command\Cli\Cron; use Magento\CatalogRule\Test\Page\Adminhtml\CatalogRuleEdit; +use Magento\Mtf\TestStep\TestStepFactory; +use Magento\Mtf\Fixture\FixtureInterface; /** * Preconditions: @@ -37,57 +39,66 @@ class ApplyCatalogPriceRulesTest extends AbstractCatalogRuleEntityTest * Apply catalog price rules. * * @param array $catalogRules - * @param CatalogProductSimple $product * @param CatalogRuleEdit $catalogRuleEdit + * @param TestStepFactory $stepFactory * @param Cron $cron * @param bool $isCronEnabled * @param Customer $customer - * @return array + * @param array $products + * @return FixtureInterface[] */ public function test( array $catalogRules, - CatalogProductSimple $product, CatalogRuleEdit $catalogRuleEdit, + TestStepFactory $stepFactory, Cron $cron, $isCronEnabled = false, - Customer $customer = null + Customer $customer = null, + array $products = null ) { - $product->persist(); - - foreach ($catalogRules as $catalogPriceRule) { - $catalogPriceRule = $this->createCatalogPriceRule($catalogPriceRule, $product, $customer); + 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) + private 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]; + $result['%category_id%'] = $product->getDataFieldConfig('category_ids')['source']->getIds()[0]; break; case 'Attribute': /** @var \Magento\Catalog\Test\Fixture\CatalogProductAttribute[] $attrs */ - $attributes = $productSimple->getDataFieldConfig('attribute_set_id')['source'] + $attributes = $product->getDataFieldConfig('attribute_set_id')['source'] ->getAttributeSet()->getDataFieldConfig('assigned_attributes')['source']->getAttributes(); $result['%attribute_id%'] = $attributes[0]->getAttributeCode(); @@ -110,7 +121,6 @@ class ApplyCatalogPriceRulesTest extends AbstractCatalogRuleEntityTest */ private 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 +131,19 @@ class ApplyCatalogPriceRulesTest extends AbstractCatalogRuleEntityTest /** * Create catalog price rule. * - * @param CatalogProductSimple $product * @param array $catalogPriceRule + * @param FixtureInterface $product * @param Customer $customer * @return CatalogRule */ private 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 c732ae1f2b877b1ad95a53083a5ea82c5f27460f..00b02c61bd61cb07587fd2df00ef035d85c09b95 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 @@ -11,7 +11,7 @@ <data name="tag" xsi:type="string">test_type:extended_acceptance_test</data> <data name="catalogRules/0/dataset" xsi:type="string">catalog_price_rule_priority_0</data> <data name="catalogRules/1/dataset" xsi:type="string">catalog_price_rule_priority_2</data> - <data name="product/dataset" xsi:type="string">simple_for_salesrule_2</data> + <data name="products/0" xsi:type="string">catalogProductSimple::simple_for_salesrule_2</data> <data name="cartPrice/sub_total" xsi:type="string">15</data> <data name="cartPrice/grand_total" xsi:type="string">20</data> <data name="productPrice/0/discount_amount" xsi:type="string">35</data> @@ -26,7 +26,7 @@ <data name="catalogRules/0/dataset" xsi:type="string">catalog_price_rule_priority_0</data> <data name="catalogRules/1/dataset" xsi:type="string">catalog_price_rule_priority_1_stop_further_rules</data> <data name="catalogRules/2/dataset" xsi:type="string">catalog_price_rule_priority_2</data> - <data name="product/dataset" xsi:type="string">simple_for_salesrule_2</data> + <data name="products/0" xsi:type="string">catalogProductSimple::simple_for_salesrule_2</data> <data name="cartPrice/sub_total" xsi:type="string">20</data> <data name="cartPrice/grand_total" xsi:type="string">25</data> <data name="productPrice/0/discount_amount" xsi:type="string">30</data> @@ -40,7 +40,7 @@ <variation name="ApplyCatalogRules_WithExpireDate" summary="Apply Catalog Price rule with Expire Date and Catalog Price Rule with Start Date"> <data name="catalogRules/0/dataset" xsi:type="string">active_catalog_price_rule_with_conditions</data> <data name="catalogRules/1/dataset" xsi:type="string">active_catalog_rule</data> - <data name="product/dataset" xsi:type="string">simple_for_salesrule_2</data> + <data name="products/0" xsi:type="string">catalogProductSimple::simple_for_salesrule_2</data> <data name="cartPrice/sub_total" xsi:type="string">45</data> <data name="cartPrice/grand_total" xsi:type="string">50</data> <data name="productPrice/0/discount_amount" xsi:type="string">5</data> @@ -53,7 +53,7 @@ </variation> <variation name="ApplyCatalogRule_ForGuestUsers_ByProductAttribute_AdjustPriceToValue" summary="Apply Catalog Price Rule with Product Attribute in Condition" ticketId="MAGETWO-30095"> <data name="tag" xsi:type="string">test_type:extended_acceptance_test</data> - <data name="product/dataset" xsi:type="string">product_with_custom_color_attribute</data> + <data name="products/0" xsi:type="string">catalogProductSimple::product_with_custom_color_attribute</data> <data name="catalogRules/0/data/name" xsi:type="string">Catalog Price Rule %isolation%</data> <data name="catalogRules/0/data/is_active" xsi:type="string">Active</data> <data name="catalogRules/0/data/website_ids/option_0" xsi:type="string">Main Website</data> @@ -72,7 +72,7 @@ <constraint name="Magento\CatalogRule\Test\Constraint\AssertCatalogPriceRuleAppliedShoppingCart" /> </variation> <variation name="ApplyCatalogRule_ForGuestUsers_AdjustPriceToPercentage" summary="Apply Catalog Price Rule for Guest Users with Adjust Price to Percentage" ticketId="MAGETWO-23036"> - <data name="product/dataset" xsi:type="string">MAGETWO-23036</data> + <data name="products/0" xsi:type="string">catalogProductSimple::MAGETWO-23036</data> <data name="catalogRules/0/data/name" xsi:type="string">rule_name%isolation%</data> <data name="catalogRules/0/data/is_active" xsi:type="string">Active</data> <data name="catalogRules/0/data/website_ids/option_0" xsi:type="string">Main Website</data> @@ -93,7 +93,7 @@ <variation name="ApplyCatalogRule_ForNewCustomerGroup" summary="Apply Catalog Price Rules to Specific Customer Group" ticketId="MAGETWO-12908"> <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> <data name="customer/dataset" xsi:type="string">customer_with_new_customer_group</data> - <data name="product/dataset" xsi:type="string">simple_10_dollar</data> + <data name="products/0" xsi:type="string">catalogProductSimple::simple_10_dollar</data> <data name="catalogRules/0/data/name" xsi:type="string">rule_name%isolation%</data> <data name="catalogRules/0/data/is_active" xsi:type="string">Active</data> <data name="catalogRules/0/data/website_ids/option_0" xsi:type="string">Main Website</data> @@ -113,5 +113,38 @@ <constraint name="Magento\CatalogRule\Test\Constraint\AssertCatalogPriceRuleAppliedProductPage" /> <constraint name="Magento\CatalogRule\Test\Constraint\AssertCatalogPriceRuleAppliedShoppingCart" /> </variation> + <variation name="ApplyCatalogRuleForSimpleProductWithCustomOptions" summary="Apply Catalog Rule for Simple Product With Custom Options" ticketId="MAGETWO-23038"> + <data name="products/0" xsi:type="string">catalogProductSimple::with_default_custom_option</data> + <data name="products/1" xsi:type="string">catalogProductSimple::with_fixed_custom_option</data> + <data name="products/2" xsi:type="string">catalogProductSimple::with_percent_custom_option</data> + <data name="customer/dataset" xsi:type="string">customer_US</data> + <data name="catalogRules/0/data/name" xsi:type="string">CatalogPriceRule %isolation%</data> + <data name="catalogRules/0/data/is_active" xsi:type="string">Active</data> + <data name="catalogRules/0/data/website_ids/option_0" xsi:type="string">Main Website</data> + <data name="customer/data/group_id/dataset" xsi:type="string">default</data> + <data name="catalogRules/0/data/simple_action" xsi:type="string">Apply as percentage of original</data> + <data name="catalogRules/0/data/discount_amount" xsi:type="string">13</data> + <data name="catalogRules/0/data/stop_rules_processing" xsi:type="string">Yes</data> + <data name="cartPrice/sub_total" xsi:type="string">164.99</data> + <data name="cartPrice/grand_total" xsi:type="string">179.99</data> + <data name="productPrice/0/discount_amount" xsi:type="string">7.38</data> + <data name="productPrice/1/discount_amount" xsi:type="string">8.04</data> + <data name="productPrice/2/discount_amount" xsi:type="string">7.38</data> + <data name="productPrice/0/special" xsi:type="string">49.40</data> + <data name="productPrice/1/special" xsi:type="string">53.85</data> + <data name="productPrice/2/special" xsi:type="string">61.74</data> + <data name="productPrice/0/sub_total" xsi:type="string">49.40</data> + <data name="productPrice/1/sub_total" xsi:type="string">61.74</data> + <data name="productPrice/2/sub_total" xsi:type="string">53.85</data> + <data name="productPrice/0/regular" xsi:type="string">56.78</data> + <data name="productPrice/1/regular" xsi:type="string">61.98</data> + <data name="productPrice/2/regular" xsi:type="string">69.12</data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="shippingAddress/dataset" xsi:type="string">UK_address</data> + <data name="payment/method" xsi:type="string">free</data> + <constraint name="Magento\CatalogRule\Test\Constraint\AssertCatalogPriceRuleAppliedShoppingCart" /> + <constraint name="Magento\CatalogRule\Test\Constraint\AssertCatalogPriceRuleAppliedOnepageCheckout" /> + </variation> </testCase> </config> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.php index 483d6fa28636ac9f875495d277691b8f2acc3778..a10d28f5e70e35a6e64abf63bf5f69df99823eb8 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.php @@ -86,16 +86,17 @@ class Shipping extends Form */ 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."); + } } } 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 cbda80aa712f00271370c55b1555a32472e95234..231589bfdab774a2c04ed2f5ebdc07a3bf91e786 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 @@ -36,6 +36,13 @@ class Sidebar extends Block */ protected $braintreePaypalCheckoutButton = './/button[contains(@id, "braintree-paypal-mini-cart")]'; + /** + * Locator value for "Proceed to Checkout" button. + * + * @var string + */ + private $proceedToCheckoutButton = '#top-cart-btn-checkout'; + /** * Minicart items quantity * @@ -116,6 +123,16 @@ class Sidebar extends Block ->click(); } + /** + * Click "Proceed to Checkout" button. + * + * @return void + */ + public function clickProceedToCheckoutButton() + { + $this->_rootElement->find($this->proceedToCheckoutButton)->click(); + } + /** * Wait counter qty visibility. * diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/CustomAddress.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/CustomAddress.php new file mode 100644 index 0000000000000000000000000000000000000000..6905aacd4018968eb0765735eb53c9b55feac2a4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/CustomAddress.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Checkout\Test\Block\Onepage; + +use Magento\Mtf\Block\Form; +use Magento\Mtf\Client\Locator; + +/** + * Form for custom billing address filling. + */ +class CustomAddress extends Form +{ + /** + * Update billing address button. + * + * @var string + */ + private $updateButtonSelector = '.action.action-update'; + + /** + * Select address dropdown. + * + * @var string + */ + private $select = "[name='billing_address_id']"; + + /** + * Click update on billing information block. + * + * @return void + */ + public function clickUpdate() + { + $this->_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/Payment/Method/Billing.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/Method/Billing.php index 167767e518a48bb4879c076d9de6c0fd95ece128..d93c24f2641b0f2f326b60e5478537b242a51b47 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 @@ -36,6 +36,20 @@ class Billing extends Form */ protected $sameAsShippingCheckbox = '[name="billing-address-same-as-shipping"]'; + /** + * New address select selector. + * + * @var string + */ + private $newAddressSelect = '[name="billing_address_id"]'; + + /** + * New address option value. + * + * @var string + */ + private $newAddressOption = 'New Address'; + /** * Fill billing address. * @@ -44,6 +58,10 @@ class Billing extends Form */ public function fillBilling(Address $billingAddress) { + $select = $this->_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/Shipping.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.php index f2530c016b714bf5af16c2b6d0f0f6d690cc4af0..fe844bc08b0017b2aa1cabfe4a7882b3733c118a 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.php @@ -36,6 +36,39 @@ class Shipping extends Form */ private $addressModalBlock = '//*[@id="opc-new-shipping-address"]/../..'; + /** + * @var string + */ + private $selectedAddress = '.shipping-address-item.selected-item'; + + /** + * New address button selector. + * + * @var string + */ + private $popupSelector = '.action-show-popup'; + + /** + * Locator for address select button. + * + * @var string + */ + private $addressSelectButton = '.action-select-shipping-item'; + + /** + * Locator for shipping address select block. + * + * @var string + */ + private $shippingAddressBlock = '.shipping-address-item'; + + /** + * Locator for shipping address select block. + * + * @var string + */ + private $selectedShippingAddressBlock = '.selected-item'; + /** * Click on "New Address" button. * @@ -69,4 +102,63 @@ class Shipping extends Form { 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/Method.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/Method.php index d038ca0599d75a779a352622ac85213a183f8053..cce29d23f63b18fc2c469e3df964cb2dd81188e0 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 @@ -10,12 +10,12 @@ use Magento\Mtf\Block\Block; use Magento\Mtf\Client\Locator; /** - * One page checkout status shipping method block + * One page checkout status shipping method block. */ class Method extends Block { /** - * Shipping method selector + * Shipping method selector. * * @var string */ 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 0000000000000000000000000000000000000000..fa6a8fa2a28613094139eb6cb91126ab5e85763b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/ShippingPopup.php @@ -0,0 +1,32 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Checkout\Test\Block\Onepage; + +use Magento\Mtf\Block\Form; + +/** + * Checkout new shipping address popup block. + */ +class ShippingPopup extends Form +{ + /** + * Save address button selector. + * + * @var string + */ + private $saveAddressButton = '.action-save-address'; + + /** + * Click on save address button. + * + * @return void + */ + public function clickSaveAddressButton() + { + $this->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 0000000000000000000000000000000000000000..13403b792684512c9741bca74a78f7c84036eb48 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/ShippingPopup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" ?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<mapping strict="0"> + <fields> + <firstname /> + <lastname /> + <company /> + <street> + <selector>input[name="street[0]"]</selector> + </street> + <city /> + <region_id> + <input>select</input> + </region_id> + <country_id> + <input>select</input> + </country_id> + <telephone /> + <postcode /> + </fields> +</mapping> 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 0000000000000000000000000000000000000000..61fcf0f5adf8a3958050101ba053f104dc208fa3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCustomerIsRedirectedToCheckoutFromCart.php @@ -0,0 +1,115 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Checkout\Test\Constraint; + +use Magento\Sales\Test\Constraint\AssertOrderGrandTotal; +use Magento\Sales\Test\Page\Adminhtml\SalesOrderView; +use Magento\Sales\Test\Page\Adminhtml\OrderIndex; +use Magento\Cms\Test\Page\CmsIndex; +use Magento\Checkout\Test\Page\CheckoutOnepage; +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Mtf\TestStep\TestStepFactory; + +/** + * Assert first step on Checkout page is available. + * Assert that Order Grand Total is correct on order page in backend. + */ +class AssertCustomerIsRedirectedToCheckoutFromCart extends AbstractConstraint +{ + /** + * Factory for Test Steps. + * + * @var TestStepFactory + */ + private $stepFactory; + + /** + * Order Id. + * + * @var string + */ + private $orderId; + + /** + * Assert first step on Checkout page is available. + * Assert that Order Grand Total is correct on order page in backend. + * + * @param CmsIndex $cmsIndex + * @param CheckoutOnepage $checkoutOnepage + * @param TestStepFactory $stepFactory + * @param AssertOrderGrandTotal $assertOrderGrandTotal + * @param SalesOrderView $salesOrderView + * @param OrderIndex $orderIndex + * @param array $prices + * @param array $checkoutData + * @return void + */ + public function processAssert( + CmsIndex $cmsIndex, + CheckoutOnepage $checkoutOnepage, + TestStepFactory $stepFactory, + AssertOrderGrandTotal $assertOrderGrandTotal, + SalesOrderView $salesOrderView, + OrderIndex $orderIndex, + array $prices, + array $checkoutData = [] + ) { + $this->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/AssertProductDataInMiniShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductDataInMiniShoppingCart.php index 2b10754d9b47b945bd5a87709e78b378a2a754df..3e78cfb076acb1c8d033bb3dfa0a6e44f3cfd02c 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductDataInMiniShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductDataInMiniShoppingCart.php @@ -14,12 +14,12 @@ use Magento\Mtf\Constraint\AbstractAssertForm; use Magento\Mtf\Fixture\FixtureInterface; /** - * Assert that product price and qty in mini shopping cart equal to expected price from data set. + * Assert that product price and qty in mini shopping cart are equal to expected price from data set. */ class AssertProductDataInMiniShoppingCart extends AbstractAssertForm { /** - * Assert that product price and qty in mini shopping cart are equal to expected price from data set. + * Assert that product price and qty in mini shopping cart equal to expected price from data set. * * @param CmsIndex $cmsIndex * @param Cart $cart 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 f8dcf95b0c16d87d6f7a241d1f0980b86c5c08d5..0ab3bbb2c2cfcb01330fecd582bb235ed7805068 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 @@ -8,12 +8,16 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/pages.xsd"> <page name="CheckoutOnepage" mca="checkout" module="Magento_Checkout"> <block name="authenticationPopupBlock" class="Magento\Customer\Test\Block\Account\AuthenticationPopup" locator=".block-authentication" strategy="css selector" /> + <block name="authenticationWrapperBlock" class="Magento\Customer\Test\Block\Account\AuthenticationWrapper" locator="[data-block='authentication']" strategy="css selector" /> <block name="loginBlock" class="Magento\Checkout\Test\Block\Onepage\Login" locator="[data-role='email-with-possible-login']" strategy="css selector" /> + <block name="linksBlock" class="Magento\Theme\Test\Block\Links" locator=".header .links" strategy="css selector" /> <block name="shippingBlock" class="Magento\Checkout\Test\Block\Onepage\Shipping" locator="#checkout-step-shipping" strategy="css selector" /> + <block name="shippingAddressPopupBlock" class="Magento\Checkout\Test\Block\Onepage\ShippingPopup" locator="#opc-new-shipping-address" strategy="css selector" /> <block name="shippingMethodBlock" class="Magento\Checkout\Test\Block\Onepage\Shipping\Method" locator="#checkout-step-shipping_method" strategy="css selector" /> <block name="paymentBlock" class="Magento\Checkout\Test\Block\Onepage\Payment" locator="#checkout-step-payment" strategy="css selector" /> <block name="discountCodesBlock" class="Magento\Checkout\Test\Block\Onepage\Payment\DiscountCodes" locator=".discount-code" strategy="css selector" /> <block name="reviewBlock" class="Magento\Checkout\Test\Block\Onepage\Review" locator=".opc-block-summary" strategy="css selector" /> <block name="messagesBlock" class="Magento\Backend\Test\Block\Messages" locator=".page.messages" strategy="css selector" /> + <block name="customAddressBlock" class="Magento\Checkout\Test\Block\Onepage\CustomAddress" locator=".checkout-billing-address" strategy="css selector" /> </page> </config> 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 0000000000000000000000000000000000000000..f1d9108ec3fc4e960e462fe06d2b9e8866612f97 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Repository/ConfigData.xml @@ -0,0 +1,43 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd"> + <repository class="Magento\Config\Test\Repository\ConfigData"> + <dataset name="disable_guest_checkout"> + <field name="checkout/options/guest_checkout" xsi:type="array"> + <item name="scope" xsi:type="string">checkout</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">No</item> + <item name="value" xsi:type="string">0</item> + </field> + </dataset> + <dataset name="disable_guest_checkout_rollback"> + <field name="checkout/options/guest_checkout" xsi:type="array"> + <item name="scope" xsi:type="string">checkout</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="string">1</item> + </field> + </dataset> + <dataset name="disable_customer_redirect_after_logging"> + <field name="customer/startup/redirect_dashboard" xsi:type="array"> + <item name="scope" xsi:type="string">customer</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">No</item> + <item name="value" xsi:type="string">0</item> + </field> + </dataset> + <dataset name="disable_customer_redirect_after_logging_rollback"> + <field name="customer/startup/redirect_dashboard" xsi:type="array"> + <item name="scope" xsi:type="string">customer</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="string">1</item> + </field> + </dataset> + </repository> +</config> 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 58d0c23f2274fcdde30703aa8ca4920ec0aa208a..25922102e1269c95280697db6c3175c36d6253fc 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 @@ -33,7 +33,7 @@ use Magento\Mtf\TestCase\Scenario; * 14. Perform assertions. * * @group One_Page_Checkout - * @ZephyrId MAGETWO-27485, MAGETWO-12412, MAGETWO-12429 + * @ZephyrId MAGETWO-27485, MAGETWO-12412, MAGETWO-12429, MAGETWO-49917, MAGETWO-27485 * @ZephyrId MAGETWO-12444, MAGETWO-12848, MAGETWO-12849, MAGETWO-12850 */ class OnePageCheckoutTest extends Scenario diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml index 797255d4e374acf001132647eee1121168ec0b50..24f63035645f22ebbf051f2ab0cb8cbf48c59c93 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml @@ -7,6 +7,34 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Checkout\Test\TestCase\OnePageCheckoutTest" summary="OnePageCheckout within Offline Payment Methods" ticketId="MAGETWO-27485"> + <variation name="OnePageCheckoutUsingLoginPopup" summary="Customer is redirected to checkout on login if guest is disabled, flow for existed Customer" ticketId="MAGETWO-49916"> + <data name="products/0" xsi:type="string">catalogProductSimple::default</data> + <data name="customer/dataset" xsi:type="string">johndoe_with_addresses</data> + <data name="checkoutMethod" xsi:type="string">login</data> + <data name="prices" xsi:type="array"> + <item name="grandTotal" xsi:type="string">565.00</item> + </data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="payment/method" xsi:type="string">checkmo</data> + <data name="configData" xsi:type="string">checkmo, disable_guest_checkout, disable_customer_redirect_after_logging</data> + <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> + </variation> + <variation name="OnePageCheckoutUsingRegisterLink" summary="Customer is redirected to checkout on login if guest is disabled, flow with registration new Customer" ticketId="MAGETWO-49917"> + <data name="issue" xsi:type="string">MAGETWO-59816: Redirect works improperly in a browser incognito mode</data> + <data name="products/0" xsi:type="string">catalogProductSimple::default</data> + <data name="customer/dataset" xsi:type="string">register_customer</data> + <data name="checkoutMethod" xsi:type="string">register_before_checkout</data> + <data name="prices" xsi:type="array"> + <item name="grandTotal" xsi:type="string">565.00</item> + </data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="shippingAddress/dataset" xsi:type="string">US_address_1_without_email</data> + <data name="payment/method" xsi:type="string">checkmo</data> + <data name="configData" xsi:type="string">checkmo, disable_guest_checkout, disable_customer_redirect_after_logging, enable_https_frontend_only</data> + <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> + </variation> <variation name="OnePageCheckoutTestVariation1" summary="Checkout as UK guest with virtual product and downloadable product using coupon for not logged in customers"> <data name="products/0" xsi:type="string">catalogProductVirtual::default</data> <data name="products/1" xsi:type="string">downloadableProduct::with_two_separately_links</data> @@ -168,12 +196,13 @@ <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> </variation> - <variation name="OnePageCheckoutTestVariation9" summary="One Page Checkout Products with Tier Prices"> + <variation name="OnePageCheckoutTestVariation9" summary="One Page Checkout Products with different shipping/billing address and Tier Prices" ticketId="MAGETWO-42604"> <data name="tag" xsi:type="string">stable:no</data> <data name="products/0" xsi:type="string">catalogProductSimple::simple_with_tier_price_and_order_qty_3</data> <data name="customer/dataset" xsi:type="string">default</data> - <data name="checkoutMethod" xsi:type="string">guest</data> - <data name="shippingAddress/dataset" xsi:type="string">UK_address</data> + <data name="checkoutMethod" xsi:type="string">login</data> + <data name="shippingAddress/dataset" xsi:type="string">UK_address_without_email</data> + <data name="billingAddress/dataset" xsi:type="string">UK_address_2_without_email</data> <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> <data name="shipping/shipping_method" xsi:type="string">Fixed</data> <data name="prices" xsi:type="array"> @@ -183,6 +212,7 @@ <data name="configData" xsi:type="string">banktransfer_specificcountry_gb</data> <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> <constraint name="Magento\Checkout\Test\Constraint\AssertMinicartEmpty" /> + <constraint name="Magento\Customer\Test\Constraint\AssertCustomerDefaultAddressFrontendAddressBook" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> </variation> <variation name="OnePageCheckoutTestVariation10" summary="One Page Checkout with all product types"> @@ -203,7 +233,88 @@ </data> <data name="payment/method" xsi:type="string">checkmo</data> <data name="configData" xsi:type="string">checkmo</data> + <constraint name="Magento\Customer\Test\Constraint\AssertCustomerDefaultAddressFrontendAddressBook" /> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> + </variation> + <variation name="OnePageCheckoutUsingSingInLink" summary="Login during checkout using 'Sign In' link" ticketId="MAGETWO-42547"> + <data name="products/0" xsi:type="string">catalogProductSimple::default</data> + <data name="customer/dataset" xsi:type="string">customer_UK_US_addresses</data> + <data name="checkoutMethod" xsi:type="string">sign_in</data> + <data name="shippingAddressCustomer" xsi:type="array"> + <item name="added" xsi:type="number">1</item> + </data> + <data name="billingAddressCustomer" xsi:type="array"> + <item name="added" xsi:type="number">1</item> + </data> + <data name="prices" xsi:type="array"> + <item name="grandTotal" xsi:type="string">565.00</item> + </data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="payment/method" xsi:type="string">checkmo</data> + <data name="configData" xsi:type="string">checkmo</data> + <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderAddresses" /> + </variation> + <variation name="OnePageCheckoutUsingNonDefaultAddress" summary="Checkout as Customer using non default address" ticketId="MAGETWO-42602"> + <data name="products/0" xsi:type="string">catalogProductSimple::default</data> + <data name="customer/dataset" xsi:type="string">customer_US_DE_UK</data> + <data name="checkoutMethod" xsi:type="string">login</data> + <data name="shippingAddressCustomer" xsi:type="array"> + <item name="added" xsi:type="number">1</item> + </data> + <data name="billingAddressCustomer" xsi:type="array"> + <item name="added" xsi:type="number">2</item> + </data> + <data name="prices" xsi:type="array"> + <item name="grandTotal" xsi:type="string">565.00</item> + </data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="payment/method" xsi:type="string">checkmo</data> + <data name="configData" xsi:type="string">checkmo</data> + <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderAddresses" /> + </variation> + <variation name="OnePageCheckoutUsingNewAddress" summary="Checkout as Customer using New address" ticketId="MAGETWO-42601"> + <data name="products/0" xsi:type="string">catalogProductSimple::default</data> + <data name="customer/dataset" xsi:type="string">johndoe_with_addresses</data> + <data name="checkoutMethod" xsi:type="string">sign_in</data> + <data name="prices" xsi:type="array"> + <item name="grandTotal" xsi:type="string">565.00</item> + </data> + <data name="shippingAddress/dataset" xsi:type="string">UK_address_without_email</data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="billingCheckboxState" xsi:type="string">Yes</data> + <data name="billingAddress/dataset" xsi:type="string">US_address_1_without_email</data> + <data name="payment/method" xsi:type="string">checkmo</data> + <data name="configData" xsi:type="string">checkmo</data> + <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderAddresses" /> + </variation> + <variation name="OnePageCheckoutTestVariation11" summary="Checkout as Customer using default address" ticketId="MAGETWO-42600, MAGETWO-42546"> + <data name="products/0" xsi:type="string">catalogProductSimple::default</data> + <data name="customer/dataset" xsi:type="string">customer_UK_US_addresses</data> + <data name="checkoutMethod" xsi:type="string">login</data> + <data name="shippingAddressCustomer" xsi:type="array"> + <item name="added" xsi:type="number">0</item> + </data> + <data name="billingAddressCustomer" xsi:type="array"> + <item name="added" xsi:type="number">0</item> + </data> + <data name="prices" xsi:type="array"> + <item name="grandTotal" xsi:type="string">565.00</item> + </data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="payment/method" xsi:type="string">checkmo</data> + <data name="configData" xsi:type="string">checkmo_specificcountry_gb</data> + <constraint name="Magento\Checkout\Test\Constraint\AssertOrderSuccessPlacedMessage" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrderGrandTotal" /> + <constraint name="Magento\Sales\Test\Constraint\AssertOrderAddresses" /> </variation> </testCase> </config> 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 62d773a6637bf8fdacedf62932d798dcd6d9e431..0bfe42f7fe78ced0ffb2282d69790ca42c4a1dec 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 @@ -11,6 +11,7 @@ use Magento\Cms\Test\Page\CmsIndex; use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\Fixture\FixtureInterface; use Magento\Mtf\TestCase\Injectable; +use Magento\Customer\Test\Fixture\Customer; /** * Preconditions: @@ -76,14 +77,28 @@ class UpdateProductFromMiniShoppingCartEntityTest extends Injectable /** * Update product from mini shopping cart. - * * @param array $originalProduct * @param array $checkoutData + * @param boolean $useMiniCartToEditQty + * @param array $shippingAddress + * @param array $shipping + * @param array $payment + * @param Customer $customer * @return array */ - public function test(array $originalProduct, array $checkoutData) - { + public function test( + array $originalProduct, + array $checkoutData, + $useMiniCartToEditQty = false, + $shippingAddress = null, + $shipping = null, + $payment = null, + Customer $customer = null + ) { // Preconditions: + if ($customer !== null) { + $customer->persist(); + } $product = $this->createProduct($originalProduct); $this->addToCart($product); @@ -93,16 +108,25 @@ class UpdateProductFromMiniShoppingCartEntityTest extends Injectable $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 5f9b069ab85ca92d37ac8773ac3d1694e5d6ee81..cd500a935485cd0e08981d32a53b9280a7d2ad57 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 @@ -7,12 +7,22 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Checkout\Test\TestCase\UpdateProductFromMiniShoppingCartEntityTest" summary="Update Product from Mini Shopping Cart" ticketId="MAGETWO-29812"> - <variation name="UpdateProductFromMiniShoppingCartEntityTestVariation1" summary="Update Simple"> - <data name="tag" xsi:type="string">test_type:extended_acceptance_test, to_maintain:yes</data> - <data name="originalProduct/0" xsi:type="string">catalogProductSimple::with_two_custom_option</data> - <data name="checkoutData/dataset" xsi:type="string">simple_update_mini_shopping_cart</data> + <variation name="UpdateProductFromMiniShoppingCartEntityTestVariation1" summary="Update Product Qty on Mini Shopping Cart" ticketId=" MAGETWO-35536"> + <data name="tag" xsi:type="string">test_type:extended_acceptance_test</data> + <data name="originalProduct/0" xsi:type="string">catalogProductSimple::default</data> + <data name="checkoutData/dataset" xsi:type="string">simple_order_qty_2</data> + <data name="use_minicart_to_edit_qty" xsi:type="boolean">true</data> + <data name="prices" xsi:type="array"> + <item name="grandTotal" xsi:type="string">1130</item> + </data> + <data name="customer/dataset" xsi:type="string">customer_US</data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="shippingAddress/dataset" xsi:type="string">UK_address</data> + <data name="payment/method" xsi:type="string">free</data> <constraint name="Magento\Checkout\Test\Constraint\AssertProductDataInMiniShoppingCart" /> <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" /> + <constraint name="Magento\Checkout\Test\Constraint\AssertCustomerIsRedirectedToCheckoutFromCart" /> </variation> <variation name="UpdateProductFromMiniShoppingCartEntityTestVariation2" summary="Update Configurable and verify previous product was updated to new one in shopping cart and mini shopping cart"> <data name="tag" xsi:type="string">test_type:extended_acceptance_test, to_maintain:yes</data> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillBillingInformationStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillBillingInformationStep.php index a7d432fa38b2a6a3ef05f8b883887d093baae554..720965212ad38d6d249d7ef4f1634e2c43f5deb2 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillBillingInformationStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillBillingInformationStep.php @@ -10,6 +10,8 @@ use Magento\Checkout\Test\Page\CheckoutOnepage; use Magento\Customer\Test\Fixture\Address; use Magento\Mtf\TestStep\TestStepInterface; use Magento\Checkout\Test\Constraint\AssertBillingAddressSameAsShippingCheckbox; +use Magento\Customer\Test\Fixture\Customer; +use Magento\Mtf\ObjectManager; /** * Fill billing information. @@ -37,6 +39,13 @@ class FillBillingInformationStep implements TestStepInterface */ protected $shippingAddress; + /** + * Customer fixture. + * + * @var Customer + */ + protected $customer; + /** * "Same as Shipping" checkbox value assertion. * @@ -51,45 +60,85 @@ class FillBillingInformationStep implements TestStepInterface */ protected $billingCheckboxState; + /** + * Customer shipping address data for select. + * + * @var array + */ + private $billingAddressCustomer; + + /** + * Object manager instance. + * + * @var ObjectManager $objectManager + */ + protected $objectManager; + /** * @constructor * @param CheckoutOnepage $checkoutOnepage * @param AssertBillingAddressSameAsShippingCheckbox $assertBillingAddressCheckbox + * @param Customer $customer + * @param ObjectManager $objectManager * @param Address $billingAddress * @param Address $shippingAddress * @param string $billingCheckboxState + * @param array|null $billingAddressCustomer */ public function __construct( CheckoutOnepage $checkoutOnepage, AssertBillingAddressSameAsShippingCheckbox $assertBillingAddressCheckbox, + Customer $customer, + ObjectManager $objectManager, Address $billingAddress = null, Address $shippingAddress = null, - $billingCheckboxState = null + $billingCheckboxState = null, + $billingAddressCustomer = null ) { $this->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 = null; 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 5150eb9964ba3e960e88694fcc781e7bc6d829e0..1c4e407fb8c24391da8ecf4498e1702adb0d254b 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 @@ -8,7 +8,10 @@ namespace Magento\Checkout\Test\TestStep; use Magento\Checkout\Test\Page\CheckoutOnepage; use Magento\Customer\Test\Fixture\Address; +use Magento\Mtf\Fixture\FixtureFactory; use Magento\Mtf\TestStep\TestStepInterface; +use Magento\Customer\Test\Fixture\Customer; +use Magento\Mtf\ObjectManager; /** * Fill shipping address step. @@ -20,37 +23,109 @@ class FillShippingAddressStep implements TestStepInterface * * @var CheckoutOnepage */ - protected $checkoutOnepage; + private $checkoutOnepage; /** * Address fixture. * * @var Address */ - protected $shippingAddress; + private $shippingAddress; + + /** + * Customer fixture. + * + * @var Customer + */ + private $customer; + + /** + * Customer shipping address data for select. + * + * @var array + */ + private $shippingAddressCustomer; + + /** + * Object manager instance. + * + * @var ObjectManager + */ + private $objectManager; + + /** + * Fixture factory. + * + * @var FixtureFactory + */ + private $fixtureFactory; /** * @constructor * @param CheckoutOnepage $checkoutOnepage - * @param Address $shippingAddress + * @param Customer $customer + * @param ObjectManager $objectManager + * @param FixtureFactory $fixtureFactory + * @param Address|null $shippingAddress + * @param array|null $shippingAddressCustomer */ public function __construct( CheckoutOnepage $checkoutOnepage, - Address $shippingAddress = null + Customer $customer, + ObjectManager $objectManager, + FixtureFactory $fixtureFactory, + Address $shippingAddress = null, + $shippingAddressCustomer = null ) { $this->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/SelectCheckoutMethodStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php index eef5f2fbdd03a9b7325b01aa8b5d4293e566ffbb..cb32e5f0ddfe61d9e97e8ef211ce71bfa46ee71a 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectCheckoutMethodStep.php @@ -8,6 +8,7 @@ namespace Magento\Checkout\Test\TestStep; use Magento\Mtf\TestStep\TestStepInterface; use Magento\Customer\Test\Fixture\Customer; +use Magento\Customer\Test\Page\CustomerAccountCreate; use Magento\Checkout\Test\Page\CheckoutOnepage; use Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep; @@ -51,6 +52,13 @@ class SelectCheckoutMethodStep implements TestStepInterface */ private $clickProceedToCheckoutStep; + /** + * Customer account create page instance. + * + * @var CustomerAccountCreate + */ + private $customerAccountCreatePage; + /** * Shipping carrier and method. * @@ -61,6 +69,7 @@ class SelectCheckoutMethodStep implements TestStepInterface /** * @constructor * @param CheckoutOnepage $checkoutOnepage + * @param CustomerAccountCreate $customerAccountCreatePage * @param Customer $customer * @param LogoutCustomerOnFrontendStep $logoutCustomerOnFrontend * @param ClickProceedToCheckoutStep $clickProceedToCheckoutStep @@ -69,6 +78,7 @@ class SelectCheckoutMethodStep implements TestStepInterface */ public function __construct( CheckoutOnepage $checkoutOnepage, + CustomerAccountCreate $customerAccountCreatePage, Customer $customer, LogoutCustomerOnFrontendStep $logoutCustomerOnFrontend, ClickProceedToCheckoutStep $clickProceedToCheckoutStep, @@ -76,6 +86,7 @@ class SelectCheckoutMethodStep implements TestStepInterface array $shipping = [] ) { $this->checkoutOnepage = $checkoutOnepage; + $this->customerAccountCreatePage = $customerAccountCreatePage; $this->customer = $customer; $this->logoutCustomerOnFrontend = $logoutCustomerOnFrontend; $this->clickProceedToCheckoutStep = $clickProceedToCheckoutStep; @@ -89,6 +100,17 @@ class SelectCheckoutMethodStep implements TestStepInterface * @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()) { @@ -101,17 +123,35 @@ class SelectCheckoutMethodStep implements TestStepInterface if (empty($this->shipping)) { $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/Cms/Test/TestCase/GridFilteringTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridFilteringTest.xml index 715190039162b4fdbab91af72ca564e0c0732858..0b237e506636cf1beb8ff22122c515079cda176e 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 @@ -8,7 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Ui\Test\TestCase\GridFilteringTest" summary="Grid UI Component Filtering" ticketId="MAGETWO-41329"> <variation name="CmsPageGridFiltering"> - <data name="tag" xsi:type="string">severity:S2</data> + <data name="tag" xsi:type="string">severity:S3</data> <data name="description" xsi:type="string">Verify cms page grid filtering</data> <data name="itemsCount" xsi:type="string">2</data> <data name="fixtureName" xsi:type="string">cmsPage</data> @@ -29,7 +29,7 @@ <constraint name="\Magento\Ui\Test\Constraint\AssertGridFiltering"/> </variation> <variation name="CmsBlockGridFiltering"> - <data name="tag" xsi:type="string">severity:S2</data> + <data name="tag" xsi:type="string">severity:S3</data> <data name="description" xsi:type="string">Verify cms block grid filtering</data> <data name="itemsCount" xsi:type="string">2</data> <data name="fixtureName" xsi:type="string">cmsBlock</data> 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 fc279aad59d3d7e21590be2c256f83831e7295cf..b17f32db04b23727a6583db5227dbf79d0f0d19d 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 @@ -8,7 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Ui\Test\TestCase\GridFullTextSearchTest" summary="Grid UI Component Full Text Search" ticketId="MAGETWO-41023"> <variation name="CmsPageGridFullTextSearch"> - <data name="tag" xsi:type="string">severity:S2, stable:no</data> + <data name="tag" xsi:type="string">severity:S3, stable:no</data> <data name="description" xsi:type="string">Verify cms page grid full text search</data> <data name="itemsCount" xsi:type="string">2</data> <data name="fixtureName" xsi:type="string">cmsPage</data> @@ -20,7 +20,7 @@ <constraint name="Magento\Ui\Test\Constraint\AssertGridFullTextSearch"/> </variation> <variation name="CmsBlockGridFullTextSearch"> - <data name="tag" xsi:type="string">severity:S2</data> + <data name="tag" xsi:type="string">severity:S3</data> <data name="description" xsi:type="string">Verify cms blocks grid full text search</data> <data name="itemsCount" xsi:type="string">2</data> <data name="fixtureName" xsi:type="string">cmsBlock</data> 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 1be7e61f6bd0ea27a99733a63828f438ab481215..053d32a0598ef1677cf67c83c307aa2352ac7803 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 @@ -8,7 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Ui\Test\TestCase\GridSortingTest" summary="Grid UI Component Sorting" ticketId="MAGETWO-41328"> <variation name="CmsPagesGridSorting"> - <data name="tag" xsi:type="string">severity:S2, stable:no</data> + <data name="tag" xsi:type="string">severity:S3, stable:no</data> <data name="description" xsi:type="string">Verify cms page grid sorting</data> <data name="columnsForSorting" xsi:type="array"> <item name="id" xsi:type="string">ID</item> @@ -19,7 +19,7 @@ <constraint name="Magento\Ui\Test\Constraint\AssertGridSorting"/> </variation> <variation name="CmsBlocksGridSorting"> - <data name="tag" xsi:type="string">severity:S2, stable:no</data> + <data name="tag" xsi:type="string">severity:S3, stable:no</data> <data name="description" xsi:type="string">Verify cms blocks grid sorting</data> <data name="steps" xsi:type="array"> <item name="0" xsi:type="string">-</item> 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 0000000000000000000000000000000000000000..6f3cfc48cdd553fea81ef9681f24e5799273af5e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php @@ -0,0 +1,77 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\ConfigurableProduct\Test\Constraint; + +use Magento\Catalog\Test\Page\Product\CatalogProductView; +use Magento\Cms\Test\Page\CmsIndex; +use Magento\CurrencySymbol\Test\Fixture\CurrencySymbolEntity; +use Magento\Mtf\Client\BrowserInterface; +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Mtf\Fixture\InjectableFixture; + +/** + * Assert currency rate applied on configurable product page. + */ +class AssertCurrencyRateAppliedOnProductPage extends AbstractConstraint +{ + /** + * Assert currency rate applied on configurable product page. + * + * @param BrowserInterface $browser + * @param InjectableFixture $product + * @param CatalogProductView $view + * @param CmsIndex $cmsIndex + * @param CurrencySymbolEntity $baseCurrency + * @param array $configuredPrices + * @param string $basePrice + */ + public function processAssert( + BrowserInterface $browser, + InjectableFixture $product, + CatalogProductView $view, + CmsIndex $cmsIndex, + CurrencySymbolEntity $baseCurrency, + array $configuredPrices, + $basePrice + ) { + $browser->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/Fixture/ConfigurableProduct/ConfigurableAttributesData.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct/ConfigurableAttributesData.php index 65f80eb7144638b59e61a984c27582a316e9b129..65715d116ab45780dcacae89ef987a16e9127ceb 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 @@ -277,10 +277,12 @@ class ConfigurableAttributesData extends DataSource $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/TestCase/CreateCurrencyRateTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCurrencyRateTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..6ba7729120ae909591f0703c36b83b51f2ea8aa0 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCurrencyRateTest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Directory\Test\TestCase\CreateCurrencyRateTest" summary="Create Currency Rate" ticketId="MAGETWO-36824"> + <variation name="CreateCurrencyRateTestVariation3"> + <data name="currencyRate/data/currency_from" xsi:type="string">USD</data> + <data name="currencyRate/data/currency_to" xsi:type="string">UAH</data> + <data name="currencyRate/data/rate" xsi:type="number">2.000</data> + <data name="currencySymbol/dataSet" xsi:type="string">currency_symbols_uah</data> + <data name="product" xsi:type="string">configurableProduct::default</data> + <data name="config/dataset" xsi:type="string">config_base_currency_us_display_currency_uah</data> + <data name="baseCurrency/data/code" xsi:type="string">USD</data> + <data name="basePrice" xsi:type="string">₴80.00</data> + <data name="configuredPrices" xsi:type="array"> + <item name="custom_currency" xsi:type="string">₴80.00</item> + <item name="base_currency" xsi:type="string">$40.00</item> + </data> + <data name="tag" xsi:type="string">test_type:acceptance_test</data> + <constraint name="Magento\Directory\Test\Constraint\AssertCurrencyRateSuccessSaveMessage" /> + <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertCurrencyRateAppliedOnProductPage" /> + </variation> + </testCase> +</config> 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 9df42574840d692ced41a85979d63de6bf7c467f..3a099d79d370a97b9d75afb419bd36860e559a1a 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 @@ -48,6 +48,18 @@ <item name="US Dollar" xsi:type="string">USD</item> </item> </field> + <field name="currency/options/base" xsi:type="array"> + <item name="scope" xsi:type="string">currency</item> + <item name="label" xsi:type="string">US Dollar</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="value" xsi:type="string">USD</item> + </field> + <field name="currency/options/default" xsi:type="array"> + <item name="scope" xsi:type="string">currency</item> + <item name="label" xsi:type="string">US Dollar</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="value" xsi:type="string">USD</item> + </field> </dataset> <dataset name="config_base_currency_ch"> diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationPopup.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationPopup.php index c4fcfd569490a6ac1f2ae68c2068d4f110f594bb..cc23998f60ac2ced653c294313cfa54eb98ef5a9 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationPopup.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationPopup.php @@ -18,7 +18,7 @@ class AuthenticationPopup extends Form * * @var string */ - private $login = '[name="send"]'; + private $login = '.action.action-login.secondary'; /** * Selector for loading mask element. @@ -27,6 +27,23 @@ class AuthenticationPopup extends Form */ private $loadingMask = '.loading-mask'; + /** + * 'Create an Account' button. + * + * @var string + */ + protected $createAccountButton = '.action.action-register.primary'; + + /** + * 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/AuthenticationWrapper.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationWrapper.php new file mode 100644 index 0000000000000000000000000000000000000000..56e7cf257f15c80b34144b78ae07e70405f77e3e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationWrapper.php @@ -0,0 +1,32 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Test\Block\Account; + +use Magento\Mtf\Block\Form; +use Magento\Customer\Test\Fixture\Customer; + +/** + * Authentication wrapper block. + */ +class AuthenticationWrapper extends AuthenticationPopup +{ + /** + * 'Sign In' link. + * + * @var string + */ + protected $signInLink = '[data-trigger="authentication"]'; + + /** + * Click on 'Sign In' link. + * + * @return void + */ + public function signInLinkClick() + { + $this->_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 0000000000000000000000000000000000000000..1bcb31c45dc391ed4d26457f74ed984812b3be57 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationWrapper.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" ?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<mapping strict="1"> + <fields> + <email> + <selector>[id='login-email']</selector> + </email> + <password> + <selector>[id='login-password']</selector> + </password> + </fields> +</mapping> 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 832c376e6435708e0e7e2e632f79e20e769b21cb..fa654599932c3d0726313dc5666e1af2f2e20751 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 @@ -53,6 +53,16 @@ class Renderer . "{{city}}, {{{$region}}}, {{postcode}}\n{{country_id}}\n{{depend}}T: {{telephone}}{{/depend}}" . "{{depend}}\nF: {{fax}}{{/depend}}{{depend}}\nVAT: {{vat_id}}{{/depend}}"; break; + case "html_without_company": + $outputPattern = "{{depend}}{{prefix}} {{/depend}}{{firstname}} {{depend}}{{middlename}} {{/depend}}" + . "{{lastname}}{{depend}} {{suffix}}{{/depend}}\n{{/depend}}{{street}}\n" + . "{{city}}, {{{$region}}} {{postcode}}\n{{country_id}}\n{{depend}}{{telephone}}{{/depend}}"; + break; + case "html_for_select_element": + $outputPattern = "{{depend}}{{prefix}} {{/depend}}{{firstname}} {{depend}}{{middlename}} {{/depend}}" + . "{{lastname}}{{depend}} {{suffix}}{{/depend}}, {{/depend}}{{street}}, " + . "{{city}}, {{{$region}}} {{postcode}}, {{country_id}}"; + break; case "oneline": default: $outputPattern = "{{depend}}{{prefix}} {{/depend}}{{firstname}} {{depend}}{{middlename}} {{/depend}}" diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddressFrontendAddressBook.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddressFrontendAddressBook.php index a95a0ba98e3bf7b751007fbb69ea841c77c6ceea..6ede7c49a070db88608296637595d986498e923b 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddressFrontendAddressBook.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddressFrontendAddressBook.php @@ -6,9 +6,10 @@ namespace Magento\Customer\Test\Constraint; +use Magento\Customer\Test\Block\Address\Renderer; use Magento\Customer\Test\Fixture\Address; -use Magento\Customer\Test\Page\CustomerAccountIndex; use Magento\Customer\Test\Page\CustomerAccountAddress; +use Magento\Customer\Test\Page\CustomerAccountIndex; use Magento\Mtf\Constraint\AbstractConstraint; /** @@ -20,25 +21,32 @@ class AssertCustomerDefaultAddressFrontendAddressBook extends AbstractConstraint * Asserts that Default Billing Address and Default Shipping Address equal to data from fixture. * * @param CustomerAccountIndex $customerAccountIndex - * @param CustomerAccountAddress $customerAccountAddress - * @param Address $address + * @param CustomerAccountAddress $customerAddress + * @param Address|null $shippingAddress + * @param Address|null $billingAddress * @return void */ public function processAssert( CustomerAccountIndex $customerAccountIndex, - CustomerAccountAddress $customerAccountAddress, - Address $address + CustomerAccountAddress $customerAddress, + Address $shippingAddress, + Address $billingAddress = null ) { + $customerAccountIndex->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(); + $validated = + $shippingAddressRendered == $customerAddress->getDefaultAddressBlock()->getDefaultShippingAddress(); + + 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 +60,18 @@ class AssertCustomerDefaultAddressFrontendAddressBook extends AbstractConstraint { 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/AssertCustomerGroupChangedToDefaultOnCustomerForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupChangedToDefaultOnCustomerForm.php index 392a594c25c33db5fd89aee78a4c8bdce37df0fc..e489b6faf00526721ec894c74a0e3fe0de3ee0b5 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupChangedToDefaultOnCustomerForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupChangedToDefaultOnCustomerForm.php @@ -32,7 +32,7 @@ class AssertCustomerGroupChangedToDefaultOnCustomerForm extends AbstractConstrai CustomerIndexNew $customerIndexEdit ) { $customerIndexEdit->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/Handler/Customer/Curl.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/Customer/Curl.php index ddb20b29e063a734545787c6194e1a24a894d2e8..f880983074576396646ed0dc10be2ebb12c6b708 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/Customer/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/Customer/Curl.php @@ -32,7 +32,8 @@ class Curl extends AbstractCurl implements CustomerInterface protected $mappingData = [ 'country_id' => [ 'United States' => 'US', - 'United Kingdom' => 'GB' + 'United Kingdom' => 'GB', + 'Germany' => 'DE' ], 'gender' => [ 'Male' => 1, diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/Customer/Webapi.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/Customer/Webapi.php index 8873e71610de0eafe4e7e7e2ff7afa8d25ce6eaf..aa63bfa50f052096d0468b5df6e8c12e7c1075af 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/Customer/Webapi.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/Customer/Webapi.php @@ -33,7 +33,8 @@ class Webapi extends AbstractWebapi implements CustomerInterface ], 'country_id' => [ 'United States' => 'US', - 'United Kingdom' => 'GB' + 'United Kingdom' => 'GB', + 'Germany' => 'DE' ], 'region_id' => [ 'California' => 12, diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.xml index 70191dc828af7aecada34068c5d0e93cce4736ee..8baa7ce0d9310f7e2d7a17fab8c904530cf25629 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.xml @@ -189,6 +189,18 @@ <field name="telephone" xsi:type="string">555-55-555-55</field> </dataset> + <dataset name="UK_address_2_without_email"> + <field name="firstname" xsi:type="string">Billy</field> + <field name="lastname" xsi:type="string">Holiday</field> + <field name="company" xsi:type="string">Magento %isolation%</field> + <field name="city" xsi:type="string">Liverpool</field> + <field name="street" xsi:type="string">99 Henry St</field> + <field name="postcode" xsi:type="string">SE1 7RW</field> + <field name="country_id" xsi:type="string">United Kingdom</field> + <field name="region" xsi:type="string">Liverpool</field> + <field name="telephone" xsi:type="string">555-55-555-55</field> + </dataset> + <dataset name="UK_address_without_email"> <field name="firstname" xsi:type="string">Jane</field> <field name="lastname" xsi:type="string">Doe</field> @@ -219,13 +231,25 @@ <dataset name="DE_address"> <field name="firstname" xsi:type="string">Jan</field> <field name="lastname" xsi:type="string">Jansen</field> + <field name="email" xsi:type="string">JaneDoe_%isolation%@example.com</field> <field name="company" xsi:type="string">Magento %isolation%</field> <field name="city" xsi:type="string">Berlin</field> <field name="street" xsi:type="string">Augsburger Strabe 41</field> <field name="postcode" xsi:type="string">10789</field> <field name="country_id" xsi:type="string">Germany</field> - <field name="region_id" xsi:type="string">Berlin</field> + <field name="region" xsi:type="string">Berlin</field> <field name="telephone" xsi:type="string">333-33-333-33</field> </dataset> + + <dataset name="customer_UK_US_addresses"> + <field name="firstname" xsi:type="string">John</field> + <field name="lastname" xsi:type="string">Doe%isolation%</field> + <field name="email" xsi:type="string">John.Doe%isolation%@example.com</field> + <field name="password" xsi:type="string">123123^q</field> + <field name="password_confirmation" xsi:type="string">123123^q</field> + <field name="address" xsi:type="array"> + <item name="dataset" xsi:type="string">UK_address_default_billing, US_address_default_shipping</item> + </field> + </dataset> </repository> </config> 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 0892fac420357cc04c905252eac8cb58127865f9..3be7447c91dad863564835d08b459b6addfd86f5 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 @@ -186,5 +186,30 @@ <item name="dataset" xsi:type="string">UK_address_with_VAT</item> </field> </dataset> + + <dataset name="customer_UK_US_addresses"> + <field name="firstname" xsi:type="string">John</field> + <field name="lastname" xsi:type="string">Doe%isolation%</field> + <field name="email" xsi:type="string">John.Doe%isolation%@example.com</field> + <field name="password" xsi:type="string">123123^q</field> + <field name="password_confirmation" xsi:type="string">123123^q</field> + <field name="address" xsi:type="array"> + <item name="dataset" xsi:type="string">UK_address_default_billing, US_address_default_shipping</item> + </field> + </dataset> + + <dataset name="customer_US_DE_UK"> + <field name="firstname" xsi:type="string">John</field> + <field name="lastname" xsi:type="string">Doe%isolation%</field> + <field name="group_id" xsi:type="array"> + <item name="dataset" xsi:type="string">General</item> + </field> + <field name="email" xsi:type="string">JohnDoe_%isolation%@example.com</field> + <field name="password" xsi:type="string">123123^q</field> + <field name="password_confirmation" xsi:type="string">123123^q</field> + <field name="address" xsi:type="array"> + <item name="dataset" xsi:type="string">US_address, DE_address, UK_address</item> + </field> + </dataset> </repository> </config> 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 918f723981faac5a3a919caaf99ac9e75b0bf1bd..42a3103ce33d7615fcbfd06084bebfa965769b60 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 @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Ui\Test\TestCase\GridFilteringTest" summary="Grid UI Component Filtering" ticketId="MAGETWO-41329"> <variation name="CustomerGridFiltering"> + <data name="tag" xsi:type="string">severity:S2</data> <data name="description" xsi:type="string">Verify customer page grid filtering</data> <data name="itemsCount" xsi:type="string">2</data> <data name="fixtureName" xsi:type="string">customer</data> 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 00a2955be126a67b96d6ff8b03c706fe3b98d802..ef0bf7b7cea72e941840f103bb3700d66f06404c 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 @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Ui\Test\TestCase\GridFullTextSearchTest" summary="Grid UI Component Full Text Search" ticketId="MAGETWO-41023"> <variation name="CustomerGridFullTextSearch"> + <data name="tag" xsi:type="string">severity:S2</data> <data name="description" xsi:type="string">Verify customer page grid full text search</data> <data name="itemsCount" xsi:type="string">2</data> <data name="fixtureName" xsi:type="string">customer</data> 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 b967fbd184526fd1d71fcf2055799842d0d018f1..7d6e7f6d8f1b4f3a2402e0ae1b659f60c941c63d 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 @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Ui\Test\TestCase\GridSortingTest" summary="Grid UI Component Sorting" ticketId="MAGETWO-41328"> <variation name="CustomerGridSorting"> + <data name="tag" xsi:type="string">severity:S2</data> <data name="tag" xsi:type="string">stable:no</data> <data name="description" xsi:type="string">Verify customer page grid sorting</data> <data name="columnsForSorting" xsi:type="array"> 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 34338371d45af849f54956588aee5a97c0f75ecd..b3d41a911af41d424ee6fcab048db42a8da8aa17 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 @@ -156,6 +156,10 @@ class UpdateCustomerFrontendEntityTest extends Injectable $this->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/TestStep/CreateCustomerStep.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/CreateCustomerStep.php index f3be4e8b89cfdc916426280bb63c806565226ad1..4beb9207f4f29883e035558e6ba0b1e256ea08ed 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 @@ -46,7 +46,9 @@ class CreateCustomerStep implements TestStepInterface { $this->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/Directory/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php new file mode 100644 index 0000000000000000000000000000000000000000..4b8f3825df8bab870a272e3db20864118db25079 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php @@ -0,0 +1,62 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Directory\Test\Constraint; + +use Magento\Catalog\Test\Page\Product\CatalogProductView; +use Magento\Mtf\Client\BrowserInterface; +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Mtf\Fixture\InjectableFixture; + +/** + * Assert currency rate applied on product page. + */ +class AssertCurrencyRateAppliedOnProductPage extends AbstractConstraint +{ + /** + * Assert currency rate applied on product page. + * + * @param BrowserInterface $browser + * @param InjectableFixture $product + * @param CatalogProductView $view + * @param string $basePrice + */ + public function processAssert( + BrowserInterface $browser, + InjectableFixture $product, + CatalogProductView $view, + $basePrice + ) { + $browser->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/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Directory/Test/Repository/ConfigData.xml new file mode 100644 index 0000000000000000000000000000000000000000..7046437a0f4e2916aaa21e7eca1b902794aa8b9d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Repository/ConfigData.xml @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd"> + <repository class="Magento\Config\Test\Repository\ConfigData"> + <dataset name="config_base_currency_us_display_currency_uah"> + <field name="currency/options/allow" xsi:type="array"> + <item name="scope" xsi:type="string">currency</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="value" xsi:type="array"> + <item name="Ukrainian Hryvnia" xsi:type="string">UAH</item> + <item name="US Dollar" xsi:type="string">USD</item> + </item> + </field> + <field name="currency/options/base" xsi:type="array"> + <item name="scope" xsi:type="string">currency</item> + <item name="label" xsi:type="string">US Dollar</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="value" xsi:type="string">USD</item> + </field> + <field name="currency/options/default" xsi:type="array"> + <item name="scope" xsi:type="string">currency</item> + <item name="label" xsi:type="string">Ukrainian Hryvnia</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="value" xsi:type="string">UAH</item> + </field> + </dataset> + </repository> +</config> 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 bc40a2ab98f6d913b80736346c7c06ef6f1c7f9e..c7841934035cadcf40b55931f748948427504652 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 @@ -6,11 +6,12 @@ namespace Magento\Directory\Test\TestCase; +use Magento\Catalog\Test\TestStep\CreateProductsStep; use Magento\Config\Test\Fixture\ConfigData; use Magento\Mtf\TestCase\Injectable; use Magento\Directory\Test\Fixture\CurrencyRate; -use Magento\Catalog\Test\Fixture\CatalogProductSimple; use Magento\CurrencySymbol\Test\Page\Adminhtml\SystemCurrencyIndex; +use Magento\Mtf\TestStep\TestStepFactory; /** * Preconditions: @@ -41,35 +42,48 @@ class CreateCurrencyRateTest extends Injectable */ protected $currencyIndexPage; + /** + * Test step factory. + * + * @var TestStepFactory + */ + private $stepFactory; + /** * Inject data. * * @param SystemCurrencyIndex $currencyIndexPage - * @return void + * @param TestStepFactory $stepFactory */ - public function __inject(SystemCurrencyIndex $currencyIndexPage) + public function __inject(SystemCurrencyIndex $currencyIndexPage, TestStepFactory $stepFactory) { $this->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 dd42950c18a78175ce51fb7cfce85fe7fbc85a0c..e984cad9ca327aa2a0896e44fc85e365e9f24503 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 @@ -13,12 +13,25 @@ <data name="currencyRate/data/currency_to" xsi:type="string">EUR</data> <data name="currencyRate/data/rate" xsi:type="number">0.8</data> <data name="currencySymbol/dataset" xsi:type="string">currency_symbols_eur</data> - <data name="product/dataset" xsi:type="string">simple_10_dollar</data> + <data name="product" xsi:type="string">catalogProductSimple::simple_10_dollar</data> <data name="config/dataset" xsi:type="string">config_currency_symbols_usd_and_eur</data> <data name="basePrice" xsi:type="string">$10.00</data> <data name="convertedPrice" xsi:type="string">€8.00</data> <constraint name="Magento\Directory\Test\Constraint\AssertCurrencyRateSuccessSaveMessage" /> <constraint name="Magento\Directory\Test\Constraint\AssertCurrencyRateAppliedOnCatalogPage" /> </variation> + <variation name="CreateCurrencyRateTestVariation2"> + <data name="currencyRate/data/currency_from" xsi:type="string">USD</data> + <data name="currencyRate/data/currency_to" xsi:type="string">UAH</data> + <data name="currencyRate/data/rate" xsi:type="number">2.000</data> + <data name="currencySymbol/dataSet" xsi:type="string">currency_symbols_uah</data> + <data name="product" xsi:type="string">catalogProductSimple::simple_10_dollar</data> + <data name="productData/0/custom_options/dataset" xsi:type="string">not_required_text_option</data> + <data name="config/dataset" xsi:type="string">config_base_currency_us_display_currency_uah</data> + <data name="basePrice" xsi:type="string">₴20.00</data> + <data name="tag" xsi:type="string">test_type:acceptance_test</data> + <constraint name="Magento\Directory\Test\Constraint\AssertCurrencyRateSuccessSaveMessage" /> + <constraint name="Magento\Directory\Test\Constraint\AssertCurrencyRateAppliedOnProductPage" /> + </variation> </testCase> </config> 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 f6450b86c511adb44b615d7d97c6bc8495e5049e..08d4506b3c05461975797ec3ec31a11b63674304 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 @@ -29,6 +29,40 @@ <item name="value" xsi:type="string">10</item> </field> </dataset> + <dataset name="layered_navigation_automatic_equalize_price_range"> + <field name="catalog/layered_navigation/display_product_count" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="value" label="Yes" xsi:type="string">1</item> + </field> + <field name="catalog/layered_navigation/price_range_calculation" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="value" label="Automatic (equalize price ranges)" xsi:type="string">auto</item> + </field> + </dataset> + <dataset name="layered_navigation_automatic_equalize_product_counts"> + <field name="catalog/layered_navigation/display_product_count" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="value" label="Yes" xsi:type="string">1</item> + </field> + <field name="catalog/layered_navigation/price_range_calculation" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="value" label="Automatic (equalize product counts)" xsi:type="string">improved</item> + </field> + <field name="catalog/layered_navigation/one_price_interval" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="value" xsi:type="string">0</item> + </field> + <field name="catalog/layered_navigation/interval_division_limit" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="value" xsi:type="string">3</item> + </field> + </dataset> <dataset name="layered_navigation_manual_range_10_rollback"> <field name="catalog/layered_navigation/display_product_count" xsi:type="array"> <item name="scope" xsi:type="string">default</item> @@ -41,5 +75,29 @@ <item name="value" label="Automatic (equalize price ranges)" xsi:type="string">auto</item> </field> </dataset> + <dataset name="layered_navigation_automatic_equalize_price_range_rollback"> + <field name="catalog/layered_navigation/display_product_count" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="value" label="Yes" xsi:type="string">1</item> + </field> + <field name="catalog/layered_navigation/price_range_calculation" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="value" label="Automatic (equalize price ranges)" xsi:type="string">auto</item> + </field> + </dataset> + <dataset name="layered_navigation_automatic_equalize_product_counts_rollback"> + <field name="catalog/layered_navigation/display_product_count" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="value" label="Yes" xsi:type="string">1</item> + </field> + <field name="catalog/layered_navigation/price_range_calculation" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="value" label="Automatic (equalize price ranges)" xsi:type="string">auto</item> + </field> + </dataset> </repository> </config> 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 543880aea127310181be8b7e7d5663495e8202ba..c42686f62591b21e29a5d28f1f42ba5fa1044260 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 @@ -21,7 +21,7 @@ use Magento\Mtf\TestCase\Injectable; * 3. Perform all assertions. * * @group Layered_Navigation - * @ZephyrId MAGETWO-12419 + * @ZephyrId MAGETWO-12419, MAGETWO-30617, MAGETWO-30700, MAGETWO-30702, MAGETWO-30703 */ class FilterProductListTest extends Injectable { diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/TestCase/FilterProductListTest.xml b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/TestCase/FilterProductListTest.xml index 8a9388df40c9fc32ade9df9df40c650605244f27..0737dfd0d7ad6d58a5c736fa6ec6270eac2ad1b9 100644 --- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/TestCase/FilterProductListTest.xml +++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/TestCase/FilterProductListTest.xml @@ -10,6 +10,7 @@ <variation name="FilterProductListTestVariation1"> <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> <data name="configData" xsi:type="string">layered_navigation_manual_range_10</data> + <data name="runReindex" xsi:type="string">Yes</data> <data name="category/dataset" xsi:type="string">default_anchor_subcategory</data> <data name="category/data/category_products/dataset" xsi:type="string">catalogProductSimple::product_20_dollar, configurableProduct::filterable_two_options_with_zero_price</data> <data name="layeredNavigation" xsi:type="array"> @@ -31,5 +32,66 @@ <constraint name="Magento\Catalog\Test\Constraint\AssertCategoryForAssignedProducts" /> <constraint name="Magento\LayeredNavigation\Test\Constraint\AssertFilterProductList" /> </variation> + <variation name="FilterProductListTestVariation2" ticketId="MAGETWO-30617, MAGETWO-30702"> + <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> + <data name="configData" xsi:type="string">layered_navigation_automatic_equalize_price_range</data> + <data name="runReindex" xsi:type="string">Yes</data> + <data name="category/dataset" xsi:type="string">default_anchor_subcategory</data> + <data name="category/data/category_products/dataset" xsi:type="string"> + 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 + </data> + <data name="layeredNavigation" xsi:type="array"> + <item name="filters_0" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">Price</item> + <item name="linkPattern" xsi:type="string">`^.+0\.00 - .+9\.99 3$`m</item> + <item name="products" xsi:type="string">product_0, product_1, product_2</item> + </item> + </item> + <item name="filters_1" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">Price</item> + <item name="linkPattern" xsi:type="string">`^.+10\.00 - .+19\.99 2$`m</item> + <item name="products" xsi:type="string">product_3, product_4</item> + </item> + </item> + <item name="filters_2" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">Price</item> + <item name="linkPattern" xsi:type="string">`^.+20\.00 and above 1$`m</item> + <item name="products" xsi:type="string">product_5</item> + </item> + </item> + </data> + <constraint name="Magento\Catalog\Test\Constraint\AssertCategoryForAssignedProducts" /> + <constraint name="Magento\LayeredNavigation\Test\Constraint\AssertFilterProductList" /> + </variation> + <variation name="FilterProductListTestVariation3" ticketId="MAGETWO-30700, MAGETWO-30703"> + <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> + <data name="configData" xsi:type="string">layered_navigation_automatic_equalize_product_counts</data> + <data name="runReindex" xsi:type="string">Yes</data> + <data name="category/dataset" xsi:type="string">default_anchor_subcategory</data> + <data name="category/data/category_products/dataset" xsi:type="string"> + 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 + </data> + <data name="layeredNavigation" xsi:type="array"> + <item name="filters_0" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">Price</item> + <item name="linkPattern" xsi:type="string">`^.+0\.00 - .+9\.99 3$`m</item> + <item name="products" xsi:type="string">product_0, product_1, product_2</item> + </item> + </item> + <item name="filters_1" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="title" xsi:type="string">Price</item> + <item name="linkPattern" xsi:type="string">`^.+10\.00 and above 3$`m</item> + <item name="products" xsi:type="string">product_3, product_4, product_5</item> + </item> + </item> + </data> + <constraint name="Magento\Catalog\Test\Constraint\AssertCategoryForAssignedProducts" /> + <constraint name="Magento\LayeredNavigation\Test\Constraint\AssertFilterProductList" /> + </variation> </testCase> </config> 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 0000000000000000000000000000000000000000..779740551527f48712ea40db23e74e3d5a7e4d60 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Persistent/Test/Constraint/AssertCustomerIsRedirectedToCheckout.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Persistent\Test\Constraint; + +use Magento\Checkout\Test\Page\CheckoutOnepage; +use Magento\Mtf\Constraint\AbstractConstraint; + +/** + * Assert first step on Checkout page is available. + */ +class AssertCustomerIsRedirectedToCheckout extends AbstractConstraint +{ + /** + * Assert first step on Checkout page is available. + * + * @param CheckoutOnepage $checkoutOnepage + * @return void + */ + public function processAssert(CheckoutOnepage $checkoutOnepage) + { + $checkoutOnepage->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 0000000000000000000000000000000000000000..5494453986157df4f836cd3fca77f96fa421d520 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Persistent/Test/Repository/ConfigData.xml @@ -0,0 +1,40 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd"> + <repository class="Magento\Config\Test\Repository\ConfigData"> + <dataset name="clearpersistence_on_signout"> + <field name="persistent/options/enabled" xsi:type="array"> + <item name="scope" xsi:type="string">persistent</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="number">1</item> + </field> + <field name="persistent/options/logout_clear" xsi:type="array"> + <item name="scope" xsi:type="string">persistent</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">No</item> + <item name="value" xsi:type="number">0</item> + </field> + </dataset> + + <dataset name="clearpersistence_on_signout_rollback"> + <field name="persistent/options/enabled" xsi:type="array"> + <item name="scope" xsi:type="string">persistent</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">No</item> + <item name="value" xsi:type="number">0</item> + </field> + <field name="persistent/options/logout_clear" xsi:type="array"> + <item name="scope" xsi:type="string">persistent</item> + <item name="scope_id" xsi:type="number">1</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="number">1</item> + </field> + </dataset> + </repository> +</config> 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 0000000000000000000000000000000000000000..2211f9b12e2bf95764382b9d42f9e49578071dbf --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Persistent/Test/TestCase/CheckoutWithPersistentShoppingCartTest.php @@ -0,0 +1,181 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Persistent\Test\TestCase; + +use Magento\Customer\Test\Fixture\Customer; +use Magento\Catalog\Test\Fixture\CatalogProductSimple; +use Magento\Customer\Test\Page\CustomerAccountCreate; +use Magento\Cms\Test\Page\CmsIndex; +use Magento\Catalog\Test\Page\Product\CatalogProductView; +use Magento\Checkout\Test\Page\CheckoutCart; +use Magento\Mtf\Client\BrowserInterface; +use Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep; +use Magento\Mtf\TestCase\Injectable; +use Magento\Mtf\TestStep\TestStepFactory; + +/** + * Preconditions: + * Apply configs: + * 1. Enable Persistent Shopping Cart. + * 2. Disable Clear Persistence on Sign Out. + * + * Steps: + * 1. Go to frontend. + * 2. Click Register link. + * 3. Fill registry form. + * 4. Click 'Create account' button. + * 5. Add simple product to shopping cart. + * 6. Sign out. + * + * @ZephyrId MAGETWO-45381 + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class CheckoutWithPersistentShoppingCartTest extends Injectable +{ + /** + * Config data. + * + * @string $configData + */ + private $configData; + + /** + * Customer registry page. + * + * @var CustomerAccountCreate + */ + private $customerAccountCreate; + + /** + * Cms page. + * + * @var CmsIndex $cmsIndex. + */ + private $cmsIndex; + + /** + * Frontend product view page. + * + * @var CatalogProductView + */ + private $catalogProductView; + + /** + * Interface Browser. + * + * @var BrowserInterface. + */ + private $browser; + + /** + * Page of checkout page. + * + * @var CheckoutCart + */ + private $checkoutCart; + + /** + * Customer log out step. + * + * @var LogoutCustomerOnFrontendStep + */ + private $logoutCustomerOnFrontendStep; + + /** + * Factory for Test Steps. + * + * @var TestStepFactory + */ + private $stepFactory; + + /** + * Inject data. + * + * @param CustomerAccountCreate $customerAccountCreate + * @param CmsIndex $cmsIndex + * @param LogoutCustomerOnFrontendStep $logoutCustomerOnFrontendStep + * @param CatalogProductView $catalogProductView + * @param BrowserInterface $browser + * @param CheckoutCart $checkoutCart + * @param TestStepFactory $stepFactory + * @return void + */ + public function __inject( + CustomerAccountCreate $customerAccountCreate, + CmsIndex $cmsIndex, + LogoutCustomerOnFrontendStep $logoutCustomerOnFrontendStep, + CatalogProductView $catalogProductView, + BrowserInterface $browser, + CheckoutCart $checkoutCart, + TestStepFactory $stepFactory + ) { + $this->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 0000000000000000000000000000000000000000..db4e85d066610fa472dd41da6503217d235beb03 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Persistent/Test/TestCase/CheckoutWithPersistentShoppingCartTest.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Persistent\Test\TestCase\CheckoutWithPersistentShoppingCartTest" summary="Checkout with Persistent Shopping Cart" ticketId="MAGETWO-45381"> + <variation name="RedirectCustomerToCheckoutTestVariation1" summary="Checkout with Persistent Shopping Cart"> + <data name="issue" xsi:type="string">MAGETWO-59976: Customer can't open Product on Storefront if Persistent Cart is enabled</data> + <data name="customer/dataset" xsi:type="string">register_customer</data> + <data name="configData" xsi:type="string">clearpersistence_on_signout</data> + <constraint name="Magento\Persistent\Test\Constraint\AssertCustomerIsRedirectedToCheckout" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Addresses.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Addresses.php new file mode 100644 index 0000000000000000000000000000000000000000..063f3f0d2a566bfc2443dc875324daec7f26c8a9 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Addresses.php @@ -0,0 +1,77 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Sales\Test\Block\Adminhtml\Order\View; + +use Magento\Mtf\Block\Block; +use Magento\Mtf\Client\Locator; + +/** + * Block for information about addresses on order page. + */ +class Addresses extends Block +{ + /** + * Billing address. + * + * @var string + */ + private $billingAddress = '.order-billing-address address'; + + /** + * New address button selector. + * + * @var string + */ + private $newAddressButton = '.action-show-popup'; + + /** + * Shipping address. + * + * @var string + */ + private $shippingAddress = '.order-shipping-address address'; + + /** + * Get customer's billing address from the data inside block. + * + * @return string + */ + public function getCustomerBillingAddress() + { + return $this->_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/Constraint/AssertOrderAddresses.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderAddresses.php new file mode 100644 index 0000000000000000000000000000000000000000..6964153ca3df6584b09e5942ec05434fbc5ae790 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderAddresses.php @@ -0,0 +1,62 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Sales\Test\Constraint; + +use Magento\Sales\Test\Page\Adminhtml\SalesOrderView; +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Customer\Test\Fixture\Address; + +/** + * Assert that Order Billing and Shipping addresses are correct on order page in backend. + */ +class AssertOrderAddresses extends AbstractConstraint +{ + /** + * Assert that Order Billing and Shipping addresses are correct on order page in backend. + * + * @param SalesOrderView $salesOrderView + * @param string $orderId + * @param Address $shippingAddress + * @param Address $billingAddress + * @return void + */ + public function processAssert( + SalesOrderView $salesOrderView, + $orderId, + Address $shippingAddress, + Address $billingAddress + ) { + + $selectedShippingAddress = $this->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/Page/Adminhtml/SalesOrderView.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesOrderView.xml index 674b42732d2cd955db0e05b03ef79a8021492642..39c228e63f2c6ddbf53859694cc15e03ef03b05b 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 @@ -17,5 +17,6 @@ <block name="informationBlock" class="Magento\Sales\Test\Block\Adminhtml\Order\View\Info" locator=".order-account-information" strategy="css selector" /> <block name="orderInfoBlock" class="Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info" locator="[data-ui-id='sales-order-tabs-tab-content-order-info']" strategy="css selector" /> <block name="orderInvoiceGrid" class="Magento\Sales\Test\Block\Adminhtml\Invoice\Grid" locator="//div[contains(@data-bind, 'sales_order_view_invoice_grid.sales_order_view_invoice_grid')]" strategy="xpath" /> + <block name="addressesBlock" class="Magento\Sales\Test\Block\Adminhtml\Order\View\Addresses" locator=".admin__page-section.order-addresses" strategy="css selector" /> </page> </config> diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.php index 284a09f42332fa456107017db9fb9bb5c78b3e65..218d10ad4bb1c6c6da47e04b7ac3da5963564c4a 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.php @@ -28,7 +28,7 @@ use Magento\Mtf\TestCase\Scenario; * 12. Perform all assertions. * * @group Order_Management - * @ZephyrId MAGETWO-28696 + * @ZephyrId MAGETWO-28696, MAGETWO-17063 */ class CreateOrderBackendTest extends Scenario { diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.xml index bd592e9d71aaa1e9d74279af53c80ac3b319e376..2fb8f91d6d99794a426a91663f7a8ccef531a916 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendTest.xml @@ -7,16 +7,16 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Sales\Test\TestCase\CreateOrderBackendTest" summary="Create Order from Admin within Offline Payment Methods" ticketId="MAGETWO-28696"> - <variation name="CreateOrderBackendTestVariation1"> + <variation name="CreateOrderBackendTestVariation1" ticketId="MAGETWO-17063"> <data name="description" xsi:type="string">Create order with simple product for registered US customer using Fixed shipping method and Cash on Delivery payment method</data> - <data name="products/0" xsi:type="string">catalogProductSimple::default</data> + <data name="products/0" xsi:type="string">catalogProductSimple::with_one_custom_option</data> <data name="customer/dataset" xsi:type="string">default</data> <data name="billingAddress/dataset" xsi:type="string">US_address_1_without_email</data> <data name="saveAddress" xsi:type="string">No</data> <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> <data name="shipping/shipping_method" xsi:type="string">Fixed</data> <data name="prices" xsi:type="array"> - <item name="grandTotal" xsi:type="string">565.00</item> + <item name="grandTotal" xsi:type="string">425.00</item> </data> <data name="payment/method" xsi:type="string">cashondelivery</data> <data name="status" xsi:type="string">Pending</data> 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 b4c3a7568a2a1dd4fb62fe0d013b6425d372d27d..78c2676765418ebcbbae5ed21a8b0b0cb9ab1da8 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 @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Ui\Test\TestCase\GridFilteringTest" summary="Grid UI Component Filtering" ticketId="MAGETWO-41328"> <variation name="SalesOrderGridFiltering"> + <data name="tag" xsi:type="string">severity:S2</data> <data name="tag" xsi:type="string">stable:no</data> <data name="description" xsi:type="string">Verify sales order grid filtering</data> <data name="steps" xsi:type="array"> @@ -33,6 +34,7 @@ <constraint name="\Magento\Ui\Test\Constraint\AssertGridFiltering"/> </variation> <variation name="SalesInvoiceGridFiltering"> + <data name="tag" xsi:type="string">severity:S3</data> <data name="description" xsi:type="string">Verify sales invoice grid filtering</data> <data name="steps" xsi:type="array"> <item name="0" xsi:type="string">Magento\Sales\Test\TestStep\CreateInvoiceStep</item> @@ -56,6 +58,7 @@ <constraint name="Magento\Ui\Test\Constraint\AssertGridFiltering"/> </variation> <variation name="SalesShipmentGridFiltering"> + <data name="tag" xsi:type="string">severity:S3</data> <data name="description" xsi:type="string">Verify sales shipment grid filtering</data> <data name="steps" xsi:type="array"> <item name="0" xsi:type="string">Magento\Sales\Test\TestStep\CreateShipmentStep</item> @@ -79,6 +82,7 @@ <constraint name="Magento\Ui\Test\Constraint\AssertGridFiltering"/> </variation> <variation name="SalesCreditMemoGridFiltering"> + <data name="tag" xsi:type="string">severity:S3</data> <data name="description" xsi:type="string">Verify sales credit memo grid filtering</data> <data name="steps" xsi:type="array"> <item name="0" xsi:type="array"> 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 0979d0dcbff250a7f0bdb2d5151f60004f72efd0..86278c52a1e26f28c82b799de7a1f45a1f4273e9 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 @@ -8,7 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Ui\Test\TestCase\GridFullTextSearchTest" summary="Grid UI Component Full Text Search" ticketId="MAGETWO-41023"> <variation name="SalesOrderGridFullTextSearch"> - <data name="tag" xsi:type="string">stable:no</data> + <data name="tag" xsi:type="string">severity:S2, stable:no</data> <data name="description" xsi:type="string">Verify sales order grid full text search</data> <data name="steps" xsi:type="array"> <item name="0" xsi:type="string">-</item> @@ -24,7 +24,7 @@ <constraint name="Magento\Ui\Test\Constraint\AssertGridFullTextSearch"/> </variation> <variation name="SalesInvoiceGridFullTextSearch"> - <data name="tag" xsi:type="string">stable:no</data> + <data name="tag" xsi:type="string">severity:S3, stable:no</data> <data name="description" xsi:type="string">Verify sales invoice grid full text search</data> <data name="steps" xsi:type="array"> <item name="0" xsi:type="string">Magento\Sales\Test\TestStep\CreateInvoiceStep</item> @@ -41,6 +41,7 @@ <constraint name="Magento\Ui\Test\Constraint\AssertGridFullTextSearch"/> </variation> <variation name="SalesShipmentGridFullTextSearch"> + <data name="tag" xsi:type="string">severity:S3</data> <data name="description" xsi:type="string">Verify sales shipment grid full text search</data> <data name="steps" xsi:type="array"> <item name="0" xsi:type="string">Magento\Sales\Test\TestStep\CreateShipmentStep</item> @@ -57,7 +58,7 @@ <constraint name="Magento\Ui\Test\Constraint\AssertGridFullTextSearch"/> </variation> <variation name="SalesCreditMemoGridFullTextSearch"> - <data name="tag" xsi:type="string">stable:no</data> + <data name="tag" xsi:type="string">severity:S3, stable:no</data> <data name="description" xsi:type="string">Verify sales credit memo grid full text search</data> <data name="steps" xsi:type="array"> <item name="0" xsi:type="array"> 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 f82f232625841ddfdd77e66812970a4de31efea6..75d5c7fd09d95200255119b7b00c7167eb8c0142 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 @@ -8,6 +8,7 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> <testCase name="Magento\Ui\Test\TestCase\GridSortingTest" summary="Grid UI Component Sorting" ticketId="MAGETWO-41328"> <variation name="SalesOrderGridSorting"> + <data name="tag" xsi:type="string">severity:S2</data> <data name="tag" xsi:type="string">to_maintain:yes</data> <data name="description" xsi:type="string">Verify sales order grid storting</data> <data name="steps" xsi:type="array"> @@ -27,6 +28,7 @@ <constraint name="\Magento\Ui\Test\Constraint\AssertGridSorting"/> </variation> <variation name="SalesInvoiceGridSorting"> + <data name="tag" xsi:type="string">severity:S3</data> <data name="tag" xsi:type="string">to_maintain:yes</data> <data name="description" xsi:type="string">Verify sales invoince grid storting</data> <data name="steps" xsi:type="array"> @@ -45,6 +47,7 @@ <constraint name="\Magento\Ui\Test\Constraint\AssertGridSorting"/> </variation> <variation name="SalesShipmentGridSorting"> + <data name="tag" xsi:type="string">severity:S3</data> <data name="tag" xsi:type="string">to_maintain:yes</data> <data name="description" xsi:type="string">Verify sales shipment grid storting</data> <data name="steps" xsi:type="array"> @@ -63,6 +66,7 @@ <constraint name="\Magento\Ui\Test\Constraint\AssertGridSorting"/> </variation> <variation name="SalesCreditMemoGridSorting"> + <data name="tag" xsi:type="string">severity:S3</data> <data name="tag" xsi:type="string">to_maintain:yes</data> <data name="description" xsi:type="string">Verify sales credit memo grid storting</data> <data name="steps" xsi:type="array"> diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.xml index d0ad41011004a3fef531865ca1c6265f9406684e..141638e6b31b948665a46a08d8b5ea12cc0dfc74 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.xml @@ -399,5 +399,30 @@ <constraint name="Magento\SalesRule\Test\Constraint\AssertCartPriceRuleSuccessSaveMessage" /> <constraint name="Magento\SalesRule\Test\Constraint\AssertCartPriceRuleForm" /> </variation> + <variation name="CreateSalesRuleEntityTestVariation16" summary="Variation to check free shipping"> + <data name="salesRule/data/name" xsi:type="string">Cart Price Rule1 %isolation%</data> + <data name="salesRule/data/description" xsi:type="string">Cart Price Rule Description %isolation%</data> + <data name="salesRule/data/is_active" xsi:type="string">Yes</data> + <data name="salesRule/data/website_ids/0" xsi:type="string">Main Website</data> + <data name="salesRule/data/customer_group_ids/0" xsi:type="string">NOT LOGGED IN</data> + <data name="salesRule/data/coupon_type" xsi:type="string">No Coupon</data> + <data name="salesRule/data/simple_action" xsi:type="string">Percent of product price discount</data> + <data name="salesRule/data/conditions_serialized" xsi:type="string">[Subtotal|greater than|0]</data> + <data name="salesRule/data/discount_amount" xsi:type="string">50</data> + <data name="salesRule/data/apply_to_shipping" xsi:type="string">No</data> + <data name="salesRule/data/simple_free_shipping" xsi:type="string">For matching items only</data> + <data name="salesRule/data/store_labels/0" xsi:type="string">Sales Cart Rule labels</data> + <data name="cartPrice/sub_total" xsi:type="string">100.00</data> + <data name="cartPrice/grand_total" xsi:type="string">50.00</data> + <data name="cartPrice/discount" xsi:type="string">50.00</data> + <data name="address/data/country_id" xsi:type="string">United States</data> + <data name="address/data/region_id" xsi:type="string">California</data> + <data name="address/data/postcode" xsi:type="string">95814</data> + <data name="productForSalesRule1/dataset" xsi:type="string">simple_for_salesrule_1</data> + <data name="productQuantity/productForSalesRule1" xsi:type="string">1</data> + <constraint name="Magento\SalesRule\Test\Constraint\AssertCartPriceRuleSuccessSaveMessage" /> + <constraint name="Magento\SalesRule\Test\Constraint\AssertCartPriceRuleConditionIsApplied" /> + <constraint name="Magento\SalesRule\Test\Constraint\AssertCartPriceRuleFreeShippingIsApplied" /> + </variation> </testCase> </config> diff --git a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Topmenu.php b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Topmenu.php index cc2826c6d840e9d76304ff78015c5e1d49121145..8d11cfea1295ff3f1a874cd02fa606dbf44ec4db 100644 --- a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Topmenu.php +++ b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Topmenu.php @@ -63,6 +63,26 @@ class Topmenu extends Block $category[0]->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/Ui/Test/Block/Adminhtml/Modal.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Modal.php index e7033698568343a7c71e99e5150d77225f90f702..a57616d4d4d0be023c34d3631b6b7ea29a855a03 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 @@ -41,6 +41,13 @@ class Modal extends Block */ protected $inputFieldSelector = '[data-role="promptField"]'; + /** + * Locator value for accept warning button. + * + * @var string + */ + protected $acceptWarningSelector = '.action-primary'; + /** * Modal overlay selector. * @@ -48,6 +55,13 @@ class Modal extends Block */ protected $modalOverlay = '.modals-overlay'; + /** + * Selector for spinner element. + * + * @var string + */ + protected $loadingMask = '[data-role="loader"]'; + /** * Press OK on an alert, confirm, prompt a dialog. * @@ -59,6 +73,18 @@ class Modal extends Block $this->_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 an alert, confirm, prompt a dialog. * diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridFilteringTest.php b/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridFilteringTest.php index 4b923dd4344a93be0e2bf3491c30eecf823f76ba..7a3da9b3fa7cd1d74bf0cc707f8b0be2ddc1214e 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridFilteringTest.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridFilteringTest.php @@ -28,6 +28,7 @@ use Magento\Ui\Test\Block\Adminhtml\DataGrid; class GridFilteringTest extends Injectable { /* tags */ + const SEVERITY = 'S2'; const STABLE = 'no'; const MVP = 'no'; /* end tags */ diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridFullTextSearchTest.php b/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridFullTextSearchTest.php index 510d2d61c0acd2100b295ee1422015b1833d9c36..a16d61e112a83a2b008f49d9b95e072aec06d7ec 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridFullTextSearchTest.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridFullTextSearchTest.php @@ -28,6 +28,7 @@ use Magento\Ui\Test\Block\Adminhtml\DataGrid; class GridFullTextSearchTest extends Injectable { /* tags */ + const SEVERITY = 'S2'; const STABLE = 'no'; const MVP = 'no'; /* end tags */ diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridSortingTest.php b/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridSortingTest.php index d1f543c7b989137c209bdbd63e6c4755644e9e8b..319ef215bcb142677d847a2c3e6ce0af6ba80199 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridSortingTest.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridSortingTest.php @@ -28,6 +28,7 @@ use Magento\Ui\Test\Block\Adminhtml\DataGrid; class GridSortingTest extends Injectable { /* tags */ + const SEVERITY = 'S2'; const MVP = 'no'; /* end tags */ diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Ui/Test/etc/di.xml new file mode 100644 index 0000000000000000000000000000000000000000..8982c1966306252a5d0113ac49e8efdb011e8ddb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/etc/di.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <type name="Magento\Ui\Test\Constraint\AssertGridFiltering"> + <arguments> + <argument name="severity" xsi:type="string">S2</argument> + </arguments> + </type> + <type name="Magento\Ui\Test\Constraint\AssertGridFullTextSearch"> + <arguments> + <argument name="severity" xsi:type="string">S2</argument> + </arguments> + </type> + <type name="Magento\Ui\Test\Constraint\AssertGridSorting"> + <arguments> + <argument name="severity" xsi:type="string">S2</argument> + </arguments> + </type> +</config> diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertCategoryUrlWithCustomStoreView.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertCategoryUrlWithCustomStoreView.php new file mode 100644 index 0000000000000000000000000000000000000000..a33ace2ff35ba4c8e91d028b7940244885b67f65 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertCategoryUrlWithCustomStoreView.php @@ -0,0 +1,62 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\UrlRewrite\Test\Constraint; + +use Magento\Catalog\Test\Fixture\Category; +use Magento\Cms\Test\Page\CmsIndex; +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Mtf\Client\BrowserInterface; +use Magento\Store\Test\Fixture\Store; + +/** + * Assert that Category URL key has been changed after changing Category parent. + */ +class AssertCategoryUrlWithCustomStoreView extends AbstractConstraint +{ + /** + * Assert that displayed category data on category page equals to passed from fixture. + * + * @param Store $storeView + * @param Category $childCategory + * @param Category $parentCategory + * @param Category $categoryUpdates + * @param CmsIndex $cmsIndex + * @param BrowserInterface $browser + */ + public function processAssert( + Store $storeView, + Category $childCategory, + Category $parentCategory, + Category $categoryUpdates, + CmsIndex $cmsIndex, + BrowserInterface $browser + ) { + $cmsIndex->open(); + $cmsIndex->getStoreSwitcherBlock()->selectStoreView($storeView->getName()); + $cmsIndex->getTopmenu()->hoverCategoryByName($parentCategory->getName()); + $cmsIndex->getTopmenu()->selectCategoryByName( + $childCategory->getName() + ); + $actualUrl = strtolower($parentCategory->getUrlKey() . '/' . $categoryUpdates->getUrlKey()); + $result = (bool)strpos($browser->getUrl(), $actualUrl); + + \PHPUnit_Framework_Assert::assertTrue( + $result, + "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/AssertUrlRewriteCategoryInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryInGrid.php index b94e716ceac64e0038d50dcd22499fa51c779eeb..3630bd697b8593a966f4ed93b67794b80b6da185 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 @@ -7,8 +7,8 @@ namespace Magento\UrlRewrite\Test\Constraint; use Magento\Catalog\Test\Fixture\Category; -use Magento\UrlRewrite\Test\Page\Adminhtml\UrlRewriteIndex; use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\UrlRewrite\Test\Page\Adminhtml\UrlRewriteIndex; /** * Class AssertUrlRewriteCategoryInGrid @@ -17,16 +17,20 @@ use Magento\Mtf\Constraint\AbstractConstraint; class AssertUrlRewriteCategoryInGrid extends AbstractConstraint { /** - * Assert that url rewrite category in grid + * Assert that url rewrite category in grid. * * @param Category $category * @param UrlRewriteIndex $urlRewriteIndex + * @param string $filterByPath * @return void */ - public function processAssert(Category $category, UrlRewriteIndex $urlRewriteIndex) - { + public function processAssert( + Category $category, + UrlRewriteIndex $urlRewriteIndex, + $filterByPath = 'target_path' + ) { $urlRewriteIndex->open(); - $filter = ['target_path' => strtolower($category->getUrlKey())]; + $filter = [$filterByPath => strtolower($category->getUrlKey())]; \PHPUnit_Framework_Assert::assertTrue( $urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter, true, false), 'URL Rewrite with request path "' . $category->getUrlKey() . '" is absent in grid.' @@ -34,7 +38,7 @@ class AssertUrlRewriteCategoryInGrid extends AbstractConstraint } /** - * URL rewrite category present in grid + * URL rewrite category present in grid. * * @return string */ 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 0000000000000000000000000000000000000000..659b29590622919363f3d98743208a4132ade678 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.php @@ -0,0 +1,100 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\UrlRewrite\Test\TestCase; + +use Magento\Catalog\Test\Page\Adminhtml\CatalogCategoryIndex; +use Magento\Catalog\Test\Page\Adminhtml\CatalogCategoryEdit; +use Magento\Catalog\Test\Fixture\Category; +use Magento\Mtf\TestCase\Injectable; +use Magento\Store\Test\Fixture\Store; + +/** + * Test for Url rewrites in catalog categories after changing url key for store view and moving category. + * + * Preconditions: + * 1. Create additional Store View in Main Website Store. + * 2. Create sub-categories "first-test" and "second-test" in Default Category. + * 3. Add one or more any products to created sub-categories. + * 4. Reindex and clean caches. + * + * Steps: + * 1. Log in to backend. + * 2. Navigate to Products > 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() + ); + $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 0000000000000000000000000000000000000000..d39650944a203af72f92a30ff7918f4182b6cb37 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\UrlRewrite\Test\TestCase\CategoryUrlRewriteTest" summary="Check url rewrites in catalog categories after changing url key for store view and moving category." ticketId="MAGETWO-45385"> + <variation name="CategoryUrlRewriteTestVariation1"> + <data name="storeView/dataset" xsi:type="string">custom</data> + <data name="childCategory/dataset" xsi:type="string">default</data> + <data name="childCategory/data/category_products/dataset" xsi:type="string">catalogProductSimple::default</data> + <data name="parentCategory/dataset" xsi:type="string">default</data> + <data name="parentCategory/data/category_products/dataset" xsi:type="string">catalogProductSimple::default</data> + <data name="categoryUpdates/data/use_default_url_key" xsi:type="string">No</data> + <data name="categoryUpdates/data/url_key" xsi:type="string">UrlKey%isolation%</data> + <constraint name="Magento\UrlRewrite\Test\Constraint\AssertCategoryUrlWithCustomStoreView" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserPasswordChangedSuccessfully.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserPasswordChangedSuccessfully.php new file mode 100644 index 0000000000000000000000000000000000000000..fec96f699ea65babe062ffc25d4563304ab187ac --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserPasswordChangedSuccessfully.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\User\Test\Constraint; + +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\User\Test\Page\Adminhtml\UserIndex; + +/** + * Assert to check change password error appearance. + */ +class AssertUserPasswordChangedSuccessfully extends AbstractConstraint +{ + /** + * Fail message when provided password have been in use. + */ + const FAIL_MESSAGE = 'Sorry, but this password has already been used. Please create another.'; + + /** + * Asserts that failed message equals to expected message. + * + * @param UserIndex $userIndex + * @return void + */ + public function processAssert(UserIndex $userIndex) + { + $errorMessage = $userIndex->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/TestCase/UpdatePasswordUserEntityPciRequirementsTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdatePasswordUserEntityPciRequirementsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..df95519e5ffe44c5dcc8b7d27adf2e3519eb4958 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdatePasswordUserEntityPciRequirementsTest.php @@ -0,0 +1,131 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\User\Test\TestCase; + +use Magento\Backend\Test\Page\AdminAuthLogin; +use Magento\Backend\Test\Page\Adminhtml\Dashboard; +use Magento\Mtf\Fixture\FixtureFactory; +use Magento\Mtf\TestCase\Injectable; +use Magento\User\Test\Fixture\User; +use Magento\User\Test\Page\Adminhtml\UserEdit; + +/** + * Preconditions: + * 1. Admin user with assigned full access role is created. + * + * Steps: + * 1. Login to Magento admin module with valid credentials. + * 2. Navigate to System > 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 0000000000000000000000000000000000000000..c2a24b0f102e22804b4e0e1b9c466176f8e32efa --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdatePasswordUserEntityPciRequirementsTest.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\User\Test\TestCase\UpdatePasswordUserEntityPciRequirementsTest" summary="PCI password requirements for admin users while changing a passworrd" ticketId="MAGETWO-48104"> + <variation name="UpdatePasswordUserEntityPciRequirementsTestVariation1"> + <data name="user/dataset" xsi:type="string">custom_admin_with_default_role</data> + <data name="passwords/0" xsi:type="string">123123^q0</data> + <data name="passwords/1" xsi:type="string">123123^q1</data> + <data name="passwords/2" xsi:type="string">123123^q2</data> + <data name="passwords/3" xsi:type="string">123123^q3</data> + <constraint name="Magento\User\Test\Constraint\AssertUserPasswordChangedSuccessfully" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php index 745c3afe0aa91cc794d99e7312b620128d3306b4..c32ba27b671655a47a8400391f5fc7a7671d7083 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php @@ -118,6 +118,7 @@ class AssertWidgetRecentlyComparedProducts extends AbstractConstraint protected function removeCompareProducts() { $this->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/TestCase/CreateWidgetEntityTest.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml index 225759df91f179dbd911fca662c05476c4830a69..57920ead79a7d113e37123d3603462759728393c 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 @@ -42,7 +42,7 @@ <constraint name="Magento\Widget\Test\Constraint\AssertWidgetRecentlyViewedProducts" /> </variation> <variation name="CreateWidgetEntityTestVariation4"> - <data name="tag" xsi:type="string">severity:S1, stable:no</data> + <data name="tag" xsi:type="string">severity:S1</data> <data name="widget/data/code" xsi:type="string">Recently Compared Products</data> <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data> <data name="widget/data/title" xsi:type="string">Title_%isolation%</data> diff --git a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricingTest.php b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricingTest.php index b8c72e9a3ebb19cdabc75933d56c0566e3f71bb8..4226ec190020cb4670c693ca681193b09ab30884 100644 --- a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricingTest.php +++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricingTest.php @@ -59,7 +59,9 @@ class AdvancedPricingTest extends \PHPUnit_Framework_TestCase $csvfile = uniqid('importexport_') . '.csv'; - $this->exportData($csvfile); + $exportContent = $this->exportData($csvfile); + $this->assertDiscountTypes($exportContent); + $this->importData($csvfile); while ($index > 0) { @@ -72,6 +74,24 @@ class AdvancedPricingTest extends \PHPUnit_Framework_TestCase } } + /** + * 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 e5fd4cc0d9630080eb7c06f2558b02be889f8a57..bdbd06e2d626630c993ac72052d1119b5e323fbf 100644 --- a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricingTest.php +++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricingTest.php @@ -48,34 +48,52 @@ class AdvancedPricingTest extends \PHPUnit_Framework_TestCase [ 'customer_group_id' => \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,18 +139,40 @@ class AdvancedPricingTest extends \PHPUnit_Framework_TestCase 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->assertEquals(0, $tierPrice->getExtensionAttributes()->getPercentageValue()); + $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 @@ -241,14 +281,16 @@ class AdvancedPricingTest extends \PHPUnit_Framework_TestCase 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->assertEquals(0, $tierPrice->getExtensionAttributes()->getPercentageValue()); + $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 37c0dff622f56e9bcbba0bfab9136b5aab0de4cd..0c25cb37bf220f3f453d67065bd9b46fcc7a768b 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/Catalog/Controller/Adminhtml/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php index f84c661126b04b9a30ec2ca84ef7d3f570d2a1bb..5db10afdee00284a4faa7249e273bb3d47ab5daf 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php @@ -233,7 +233,7 @@ class CategoryTest extends \Magento\TestFramework\TestCase\AbstractBackendContro 'display_mode' => 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 @@ class CategoryTest extends \Magento\TestFramework\TestCase\AbstractBackendContro '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/_files/dropdown_attribute.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/dropdown_attribute.php new file mode 100644 index 0000000000000000000000000000000000000000..56e84046b255bf89c5f6aa6c1cb75cb7c7d584ba --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/dropdown_attribute.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +/* Create attribute */ +/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ +$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->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/Eav/Model/ResourceModel/UpdateHandlerTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/UpdateHandlerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1f8b20b7b041119a0394e0d3d8b83de3aeb727c4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/UpdateHandlerTest.php @@ -0,0 +1,256 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Eav\Model\ResourceModel; + +use Magento\TestFramework\Helper\Bootstrap; + +/** + * @magentoAppArea adminhtml + * @magentoAppIsolation enabled + */ +class UpdateHandlerTest extends \Magento\TestFramework\Indexer\TestCase +{ + /** + * @covers \Magento\Eav\Model\ResourceModel\UpdateHandler::execute + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @dataProvider getAllStoresDataProvider + * @param $code + * @param $snapshotValue + * @param $newValue + * @param $expected + */ + public function testExecuteProcessForAllStores($code, $snapshotValue, $newValue, $expected) + { + if ($snapshotValue !== '-') { + $entity = Bootstrap::getObjectManager()->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 <b>html tag</b>'], //2 + ['description', '', false, 'Description with <b>html tag</b>'], //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 <b>html tag</b>'], //6 + ['description', 'not_empty_value', false, 'Description with <b>html tag</b>'], //7 + + ['description', null, 'not_empty_value', 'not_empty_value'], //8 + ['description', null, '', null], //9 + ['description', null, false, 'Description with <b>html tag</b>'], //10 + + ['description', false, 'not_empty_value', 'not_empty_value'], //11 + ['description', false, '', null], //12 + ['description', false, null, 'Description with <b>html tag</b>'], //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/Tax/Model/Sales/Total/Quote/SubtotalTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SubtotalTest.php index 383cc31a84228631d62864e9e2f6c2d78551d9d5..41b0fdaff08c5b0b8b7291347a2a121cf0a4c68b 100644 --- a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SubtotalTest.php +++ b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SubtotalTest.php @@ -125,6 +125,7 @@ class SubtotalTest extends \PHPUnit_Framework_TestCase $this->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/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 0000000000000000000000000000000000000000..8785e41c2920c9e5f132ab3fda3270611f10838b --- /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 © 2016 Magento. 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/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 db5855b0a692bb7ac0c9b75de35d228abe309016..5d75b8c595366169166d3964bbd95d988b1d5606 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 @@ -121,7 +121,7 @@ define([ { value: 'valLast' }]; - model.caption = false; + model.caption(''); expect(model.normalizeData('')).toEqual('valFirst'); }); }); diff --git a/lib/internal/Magento/Framework/View/Asset/MergeStrategy/Checksum.php b/lib/internal/Magento/Framework/View/Asset/MergeStrategy/Checksum.php index bfdd516de7e366a3df4773776abec8e118b3916f..44b5bb65c49d36f690490e130f68c3868f162ce6 100644 --- a/lib/internal/Magento/Framework/View/Asset/MergeStrategy/Checksum.php +++ b/lib/internal/Magento/Framework/View/Asset/MergeStrategy/Checksum.php @@ -6,6 +6,8 @@ namespace Magento\Framework\View\Asset\MergeStrategy; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\View\Asset\Source; /** * Skip merging if all of the files that need to be merged were not modified @@ -25,6 +27,11 @@ class Checksum implements \Magento\Framework\View\Asset\MergeStrategyInterface */ protected $filesystem; + /** + * @var Source + */ + private $assetSource; + /** * @param \Magento\Framework\View\Asset\MergeStrategyInterface $strategy * @param \Magento\Framework\Filesystem $filesystem @@ -37,17 +44,31 @@ class Checksum implements \Magento\Framework\View\Asset\MergeStrategyInterface $this->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/Test/Unit/Asset/MergeStrategy/ChecksumTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MergeStrategy/ChecksumTest.php index 9c7859116c4cbcc3da0947e6a39e5f1295dc4a8b..b20420640ebe42b31472299b2879f2f13f6abbe1 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MergeStrategy/ChecksumTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MergeStrategy/ChecksumTest.php @@ -8,6 +8,7 @@ namespace Magento\Framework\View\Test\Unit\Asset\MergeStrategy; use \Magento\Framework\View\Asset\MergeStrategy\Checksum; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\View\Asset\Source; class ChecksumTest extends \PHPUnit_Framework_TestCase { @@ -31,6 +32,11 @@ class ChecksumTest extends \PHPUnit_Framework_TestCase */ private $resultAsset; + /** + * @var Source|\PHPUnit_Framework_MockObject_MockObject + */ + private $assetSource; + /** * @var \Magento\Framework\View\Asset\MergeStrategy\Checksum */ @@ -53,6 +59,15 @@ class ChecksumTest extends \PHPUnit_Framework_TestCase ->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 @@ class ChecksumTest extends \PHPUnit_Framework_TestCase 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'));