Skip to content

Commit 5cd51d4

Browse files
committed
Merge remote-tracking branch 'origin/2.4-develop' into mftf/module-cms-staging
2 parents d013eff + 3a55648 commit 5cd51d4

File tree

175 files changed

+7000
-917
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

175 files changed

+7000
-917
lines changed

app/code/Magento/Analytics/Test/Mftf/Test/AdminAdvancedReportingNavigateMenuTest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<argument name="submenuUiId" value="{{AdminMenuReportsBusinessIntelligenceAdvancedReporting.dataUiId}}"/>
3131
</actionGroup>
3232
<switchToNextTab stepKey="switchToNewTab"/>
33+
<waitForPageLoad stepKey="waitForAdvancedReportingPageLoad"/>
3334
<seeInCurrentUrl url="advancedreporting.rjmetrics.com/report" stepKey="seeAssertAdvancedReportingPageUrl"/>
3435
</test>
3536
</tests>

app/code/Magento/Bundle/view/base/web/js/price-bundle.js

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ define([
2828
controlContainer: 'dd', // should be eliminated
2929
priceFormat: {},
3030
isFixedPrice: false,
31-
optionTierPricesBlocksSelector: '#option-tier-prices-{1} [data-role="selection-tier-prices"]'
31+
optionTierPricesBlocksSelector: '#option-tier-prices-{1} [data-role="selection-tier-prices"]',
32+
isOptionsInitialized: false
3233
};
3334

3435
$.widget('mage.priceBundle', {
@@ -53,20 +54,37 @@ define([
5354
priceBox = $(this.options.priceBoxSelector, form),
5455
qty = $(this.options.qtyFieldSelector, form);
5556

56-
if (priceBox.data('magePriceBox') &&
57-
priceBox.priceBox('option') &&
58-
priceBox.priceBox('option').priceConfig
59-
) {
60-
if (priceBox.priceBox('option').priceConfig.optionTemplate) {
61-
this._setOption('optionTemplate', priceBox.priceBox('option').priceConfig.optionTemplate);
57+
this._updatePriceBox();
58+
priceBox.on('price-box-initialized', this._updatePriceBox.bind(this));
59+
options.on('change', this._onBundleOptionChanged.bind(this));
60+
qty.on('change', this._onQtyFieldChanged.bind(this));
61+
},
62+
63+
/**
64+
* Update price box config with bundle option prices
65+
* @private
66+
*/
67+
_updatePriceBox: function () {
68+
var form = this.element,
69+
options = $(this.options.productBundleSelector, form),
70+
priceBox = $(this.options.priceBoxSelector, form);
71+
72+
if (!this.options.isOptionsInitialized) {
73+
if (priceBox.data('magePriceBox') &&
74+
priceBox.priceBox('option') &&
75+
priceBox.priceBox('option').priceConfig
76+
) {
77+
if (priceBox.priceBox('option').priceConfig.optionTemplate) { //eslint-disable-line max-depth
78+
this._setOption('optionTemplate', priceBox.priceBox('option').priceConfig.optionTemplate);
79+
}
80+
this._setOption('priceFormat', priceBox.priceBox('option').priceConfig.priceFormat);
81+
priceBox.priceBox('setDefault', this.options.optionConfig.prices);
82+
this.options.isOptionsInitialized = true;
6283
}
63-
this._setOption('priceFormat', priceBox.priceBox('option').priceConfig.priceFormat);
64-
priceBox.priceBox('setDefault', this.options.optionConfig.prices);
84+
this._applyOptionNodeFix(options);
6585
}
66-
this._applyOptionNodeFix(options);
6786

68-
options.on('change', this._onBundleOptionChanged.bind(this));
69-
qty.on('change', this._onQtyFieldChanged.bind(this));
87+
return this;
7088
},
7189

7290
/**

app/code/Magento/Catalog/Api/Data/ProductRender/FormattedPriceInfoInterface.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public function getFinalPrice();
2929

3030
/**
3131
* Set the final price: usually it calculated as minimal price of the product
32+
*
3233
* Can be different depends on type of product
3334
*
3435
* @param string $finalPrice
@@ -39,6 +40,7 @@ public function setFinalPrice($finalPrice);
3940

4041
/**
4142
* Retrieve max price of a product
43+
*
4244
* E.g. for product with custom options is price with the most expensive custom option
4345
*
4446
* @return string
@@ -57,6 +59,7 @@ public function setMaxPrice($maxPrice);
5759

5860
/**
5961
* Retrieve the minimal price of the product or variation
62+
*
6063
* The minimal price is for example, the lowest price of all variations for complex product
6164
*
6265
* @return string
@@ -66,7 +69,7 @@ public function getMinimalPrice();
6669

6770
/**
6871
* Set max regular price
69-
* Max regular price is the same, as maximum price, except of excluding calculating special price and catalogules
72+
* Max regular price is the same, as maximum price, except of excluding calculating special price and catalog rules
7073
* in it
7174
*
7275
* @param string $maxRegularPrice
@@ -130,6 +133,7 @@ public function setMinimalPrice($minimalPrice);
130133

131134
/**
132135
* Regular price - is price of product without discounts and special price with taxes and fixed product tax
136+
*
133137
* Usually this price is corresponding to price in admin panel of product
134138
*
135139
* @return string

app/code/Magento/Catalog/Controller/Adminhtml/Product/AddAttributeToTemplate.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
use Magento\Eav\Api\Data\AttributeGroupInterfaceFactory;
1818
use Magento\Eav\Api\Data\AttributeInterface;
1919
use Magento\Eav\Api\Data\AttributeSetInterface;
20+
use Magento\Eav\Model\Cache\Type as CacheType;
2021
use Magento\Framework\Api\ExtensionAttributesFactory;
2122
use Magento\Framework\Api\SearchCriteriaBuilder;
2223
use Magento\Framework\App\Action\HttpPostActionInterface;
24+
use Magento\Framework\App\CacheInterface;
2325
use Magento\Framework\App\ObjectManager;
2426
use Magento\Framework\Controller\Result\Json;
2527
use Magento\Framework\Controller\Result\JsonFactory;
@@ -29,7 +31,7 @@
2931
use Psr\Log\LoggerInterface;
3032

3133
/**
32-
* Class AddAttributeToTemplate
34+
* Assign attribute to attribute set.
3335
*
3436
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
3537
*/
@@ -80,6 +82,11 @@ class AddAttributeToTemplate extends Product implements HttpPostActionInterface
8082
*/
8183
protected $extensionAttributesFactory;
8284

85+
/**
86+
* @var CacheInterface
87+
*/
88+
private $cache;
89+
8390
/**
8491
* Constructor
8592
*
@@ -94,8 +101,8 @@ class AddAttributeToTemplate extends Product implements HttpPostActionInterface
94101
* @param AttributeManagementInterface $attributeManagement
95102
* @param LoggerInterface $logger
96103
* @param ExtensionAttributesFactory $extensionAttributesFactory
104+
* @param CacheInterface|null $cache
97105
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
98-
* @SuppressWarnings(PHPMD.LongVariable)
99106
* @SuppressWarnings(PHPMD.NPathComplexity)
100107
*/
101108
public function __construct(
@@ -109,7 +116,8 @@ public function __construct(
109116
SearchCriteriaBuilder $searchCriteriaBuilder = null,
110117
AttributeManagementInterface $attributeManagement = null,
111118
LoggerInterface $logger = null,
112-
ExtensionAttributesFactory $extensionAttributesFactory = null
119+
ExtensionAttributesFactory $extensionAttributesFactory = null,
120+
CacheInterface $cache = null
113121
) {
114122
parent::__construct($context, $productBuilder);
115123
$this->resultJsonFactory = $resultJsonFactory;
@@ -129,6 +137,7 @@ public function __construct(
129137
->get(LoggerInterface::class);
130138
$this->extensionAttributesFactory = $extensionAttributesFactory ?: ObjectManager::getInstance()
131139
->get(ExtensionAttributesFactory::class);
140+
$this->cache = $cache ?? ObjectManager::getInstance()->get(CacheInterface::class);
132141
}
133142

134143
/**
@@ -203,6 +212,7 @@ function (AttributeInterface $attribute) use ($attributeSet, $attributeGroup) {
203212
);
204213
}
205214
);
215+
$this->cache->clean([CacheType::CACHE_TAG]);
206216
} catch (LocalizedException $e) {
207217
$response->setError(true);
208218
$response->setMessage($e->getMessage());
@@ -223,7 +233,7 @@ function (AttributeInterface $attribute) use ($attributeSet, $attributeGroup) {
223233
*/
224234
private function getBasicAttributeSearchCriteriaBuilder()
225235
{
226-
$attributeIds = (array) $this->getRequest()->getParam('attributeIds', []);
236+
$attributeIds = (array)$this->getRequest()->getParam('attributeIds', []);
227237

228238
if (empty($attributeIds['selected'])) {
229239
throw new LocalizedException(__('Attributes were missing and must be specified.'));

app/code/Magento/Catalog/Model/Indexer/Category/Flat/Action/Full.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ protected function populateFlatTables(array $stores)
7979
}
8080
$category['store_id'] = $store->getId();
8181
$data[] = $this->prepareValuesToInsert(
82+
// phpcs:ignore Magento2.Performance.ForeachArrayMerge
8283
array_merge($category, $attributesData[$category[$linkField]])
8384
);
8485
}
@@ -183,7 +184,7 @@ private function getActualStoreTablesForCategoryFlat(): array
183184
foreach ($this->storeManager->getStores() as $store) {
184185
$actualStoreTables[] = sprintf(
185186
'%s_store_%s',
186-
$this->connection->getTableName('catalog_category_flat'),
187+
$this->connection->getTableName($this->getTableName('catalog_category_flat')),
187188
$store->getId()
188189
);
189190
}
@@ -199,7 +200,7 @@ private function getActualStoreTablesForCategoryFlat(): array
199200
private function deleteAbandonedStoreCategoryFlatTables(): void
200201
{
201202
$existentTables = $this->connection->getTables(
202-
$this->connection->getTableName('catalog_category_flat_store_%')
203+
$this->connection->getTableName($this->getTableName('catalog_category_flat_store_%'))
203204
);
204205
$actualStoreTables = $this->getActualStoreTablesForCategoryFlat();
205206

app/code/Magento/Catalog/Model/Indexer/Product/Flat/AbstractAction.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ protected function _updateRelationProducts($storeId, $productIds = null)
222222
['t' => $this->_productIndexerHelper->getTable($relation->getTable())],
223223
['entity_table.entity_id', $relation->getChildFieldName(), new \Zend_Db_Expr('1')]
224224
)->join(
225-
['entity_table' => $this->_connection->getTableName('catalog_product_entity')],
225+
['entity_table' => $this->_productIndexerHelper->getTable('catalog_product_entity')],
226226
"entity_table.{$metadata->getLinkField()} = t.{$relation->getParentFieldName()}",
227227
[]
228228
)->join(
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
11+
<actionGroup name="AdminExpandProductAttributesTabActionGroup">
12+
<annotations>
13+
<description>Expands the 'Attributes' tab on the Admin Product page.</description>
14+
</annotations>
15+
16+
<scrollTo selector="{{AdminProductAttributeSection.attributeSectionHeader}}" stepKey="scrollToAttributesTab"/>
17+
<conditionalClick selector="{{AdminProductAttributeSection.attributeSectionHeader}}" dependentSelector="{{AdminProductAttributeSection.attributeSection}}" visible="false" stepKey="expandAttributesTab"/>
18+
</actionGroup>
19+
</actionGroups>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
11+
<actionGroup name="AssertStorefrontAttributeOptionPresentInLayeredNavigationActionGroup">
12+
<annotations>
13+
<description>Clicks on the attribute label. Checks for attribute option presence.</description>
14+
</annotations>
15+
<arguments>
16+
<argument name="attributeLabel" type="string" defaultValue="{{ProductAttributeFrontendLabel.label}}"/>
17+
<argument name="attributeOptionLabel" type="string" defaultValue="{{Option1Store0.label}}"/>
18+
<argument name="attributeOptionPosition" type="string" defaultValue="1"/>
19+
</arguments>
20+
21+
<waitForElementVisible selector="{{StorefrontCategorySidebarSection.filterOptionsTitle(attributeLabel)}}" stepKey="waitForAttributeVisible"/>
22+
<conditionalClick selector="{{StorefrontCategorySidebarSection.filterOptionsTitle(attributeLabel)}}" dependentSelector="{{StorefrontCategorySidebarSection.activeFilterOptions}}" visible="false" stepKey="clickToExpandAttribute"/>
23+
<waitForElementVisible selector="{{StorefrontCategorySidebarSection.activeFilterOptions}}" stepKey="waitForAttributeOptionsVisible"/>
24+
<see selector="{{StorefrontCategorySidebarSection.activeFilterOptionItemByPosition(attributeOptionPosition)}}" userInput="{{attributeOptionLabel}}" stepKey="assertAttributeOptionInLayeredNavigation"/>
25+
</actionGroup>
26+
</actionGroups>

app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategorySidebarSection.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
<element name="optionQty" type="text" selector=".filter-options-content .item .count"/>
1616
<element name="filterOptionByLabel" type="button" selector=" div.filter-options-item div[option-label='{{optionLabel}}']" parameterized="true"/>
1717
<element name="removeFilter" type="button" selector="div.filter-current .remove"/>
18+
<element name="activeFilterOptions" type="text" selector=".filter-options-item.active .items"/>
19+
<element name="activeFilterOptionItemByPosition" type="text" selector=".filter-options-item.active .items li:nth-child({{itemPosition}}) a" parameterized="true"/>
1820
</section>
1921
<section name="StorefrontCategorySidebarMobileSection">
2022
<element name="shopByButton" type="button" selector="//div[contains(@class, 'filter-title')]/strong[contains(text(), 'Shop By')]"/>
2123
</section>
22-
</sections>
24+
</sections>
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
10+
<test name="AdminCheckCustomAttributeValuesAfterProductSaveTest">
11+
<annotations>
12+
<features value="Catalog"/>
13+
<stories value="Product attributes"/>
14+
<title value="Saving custom attribute values using UI"/>
15+
<description value="Checks that saved custom attribute values are reflected on the product's edit page"/>
16+
<severity value="MAJOR"/>
17+
<testCaseId value="MC-29653"/>
18+
<useCaseId value="MC-29023"/>
19+
<group value="catalog"/>
20+
</annotations>
21+
<before>
22+
<!-- Create multi select product attribute -->
23+
<createData entity="productAttributeMultiselectTwoOptions" stepKey="createMultiSelectProductAttribute"/>
24+
<!-- Add options to created product attribute -->
25+
<createData entity="productAttributeOption1" stepKey="addFirstOptionToAttribute">
26+
<requiredEntity createDataKey="createMultiSelectProductAttribute"/>
27+
</createData>
28+
<createData entity="productAttributeOption2" stepKey="addSecondOptionToAttribute">
29+
<requiredEntity createDataKey="createMultiSelectProductAttribute"/>
30+
</createData>
31+
<createData entity="productAttributeOption3" stepKey="addThirdOptionToAttribute">
32+
<requiredEntity createDataKey="createMultiSelectProductAttribute"/>
33+
</createData>
34+
<!-- Create simple product -->
35+
<createData entity="SimpleProduct2" stepKey="createSimpleProduct"/>
36+
<magentoCLI command="indexer:reindex" arguments="catalogsearch_fulltext" stepKey="reindexCatalogSearch"/>
37+
<!-- Login to Admin page -->
38+
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
39+
</before>
40+
<after>
41+
<!-- Delete created entities -->
42+
<deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/>
43+
<deleteData createDataKey="createMultiSelectProductAttribute" stepKey="deleteMultiSelectProductAttribute"/>
44+
<!-- Logout from Admin page -->
45+
<actionGroup ref="logout" stepKey="logoutFromAdmin"/>
46+
</after>
47+
48+
<!-- Open created product for edit -->
49+
<amOnPage url="{{AdminProductEditPage.url($createSimpleProduct.id$)}}" stepKey="goToProductEditPage"/>
50+
<waitForPageLoad stepKey="waitForProductPageLoad"/>
51+
52+
<!-- Add created attribute to the product -->
53+
<actionGroup ref="AddProductAttributeInProductModalActionGroup" stepKey="addAttributeToProduct">
54+
<argument name="attributeCode" value="$createMultiSelectProductAttribute.attribute_code$"/>
55+
</actionGroup>
56+
<waitForPageLoad stepKey="waitForAttributeAdded"/>
57+
58+
<!-- Expand 'Attributes' tab -->
59+
<actionGroup ref="AdminExpandProductAttributesTabActionGroup" stepKey="expandAttributesTab"/>
60+
<!-- Check created attribute presents in the 'Attributes' tab -->
61+
<seeElement selector="{{AdminProductAttributesSection.attributeDropdownByCode($createMultiSelectProductAttribute.attribute_code$)}}" stepKey="assertAttributeIsPresentInTab"/>
62+
<!-- Select attribute options -->
63+
<selectOption selector="{{AdminProductAttributesSection.attributeDropdownByCode($createMultiSelectProductAttribute.attribute_code$)}}" parameterArray="[$addFirstOptionToAttribute.option[store_labels][0][label]$, $addThirdOptionToAttribute.option[store_labels][0][label]$]" stepKey="selectAttributeOptions"/>
64+
<!-- Save product -->
65+
<actionGroup ref="SaveProductFormActionGroup" stepKey="saveProductForm"/>
66+
67+
<!-- Check attribute options are selected -->
68+
<actionGroup ref="AdminExpandProductAttributesTabActionGroup" stepKey="expandAttributesTabAfterProductSave"/>
69+
<seeOptionIsSelected selector="{{AdminProductAttributesSection.attributeDropdownByCode($createMultiSelectProductAttribute.attribute_code$)}}" userInput="$addFirstOptionToAttribute.option[store_labels][0][label]$" stepKey="assertFirstOptionIsSelected"/>
70+
<seeOptionIsSelected selector="{{AdminProductAttributesSection.attributeDropdownByCode($createMultiSelectProductAttribute.attribute_code$)}}" userInput="$addThirdOptionToAttribute.option[store_labels][0][label]$" stepKey="assertThirdOptionIsSelected"/>
71+
72+
<!-- Search for the product on Storefront -->
73+
<amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToHomePage"/>
74+
<waitForPageLoad stepKey="waitForHomePageLoad"/>
75+
<actionGroup ref="StorefrontCheckQuickSearchActionGroup" stepKey="searchProductOnStorefront">
76+
<argument name="phrase" value="$createSimpleProduct.name$"/>
77+
</actionGroup>
78+
79+
<!-- Assert that attribute values present in layered navigation -->
80+
<actionGroup ref="AssertStorefrontAttributeOptionPresentInLayeredNavigationActionGroup" stepKey="assertFirstAttributeOptionPresence">
81+
<argument name="attributeLabel" value="$createMultiSelectProductAttribute.attribute[frontend_labels][0][label]$"/>
82+
<argument name="attributeOptionLabel" value="$addFirstOptionToAttribute.option[store_labels][0][label]$"/>
83+
<argument name="attributeOptionPosition" value="1"/>
84+
</actionGroup>
85+
<actionGroup ref="AssertStorefrontAttributeOptionPresentInLayeredNavigationActionGroup" stepKey="assertThirdAttributeOptionPresence">
86+
<argument name="attributeLabel" value="$createMultiSelectProductAttribute.attribute[frontend_labels][0][label]$"/>
87+
<argument name="attributeOptionLabel" value="$addThirdOptionToAttribute.option[store_labels][0][label]$"/>
88+
<argument name="attributeOptionPosition" value="2"/>
89+
</actionGroup>
90+
</test>
91+
</tests>

0 commit comments

Comments
 (0)