Skip to content

Commit dd602f7

Browse files
committed
MAGETWO-75086: Child product image should be shown in Wishist if options are selected for configurable product #8168
1 parent 7ebf409 commit dd602f7

File tree

53 files changed

+1172
-410
lines changed

Some content is hidden

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

53 files changed

+1172
-410
lines changed

app/code/Magento/Catalog/Block/Product/ImageBuilder.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,6 @@ protected function getRatio(\Magento\Catalog\Helper\Image $helper)
121121
*/
122122
public function create()
123123
{
124-
/** @var \Magento\Catalog\Model\Product\Configuration\Item\Option\OptionInterface $simpleOption */
125-
$simpleOption = $this->product->getOptionById('simple_product');
126-
127-
if ($simpleOption !== null) {
128-
$optionProduct = $simpleOption->getProduct();
129-
$this->setProduct($optionProduct);
130-
}
131-
132124
/** @var \Magento\Catalog\Helper\Image $helper */
133125
$helper = $this->helperFactory->create()
134126
->init($this->product, $this->imageId);
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Model\Product\Configuration\Item;
9+
10+
use Magento\Catalog\Api\Data\ProductInterface;
11+
use Magento\Framework\App\ObjectManager;
12+
13+
/**
14+
* {@inheritdoc}
15+
*/
16+
class ItemResolverComposite implements ItemResolverInterface
17+
{
18+
/**
19+
* @var string[]
20+
*/
21+
private $itemResolvers = [];
22+
23+
/**
24+
* @var ItemResolverInterface[]
25+
*/
26+
private $itemResolversInstances = [];
27+
28+
/**
29+
* @param string[] $itemResolvers
30+
*/
31+
public function __construct(array $itemResolvers)
32+
{
33+
$this->itemResolvers = $itemResolvers;
34+
}
35+
36+
/**
37+
* {@inheritdoc}
38+
*/
39+
public function getFinalProduct(ItemInterface $item): ProductInterface
40+
{
41+
$finalProduct = $item->getProduct();
42+
43+
foreach ($this->itemResolvers as $resolver) {
44+
$resolvedProduct = $this->getItemResolverInstance($resolver)->getFinalProduct($item);
45+
if ($resolvedProduct !== $finalProduct) {
46+
$finalProduct = $resolvedProduct;
47+
break;
48+
}
49+
}
50+
51+
return $finalProduct;
52+
}
53+
54+
/**
55+
* Get the instance of the item resolver by class name.
56+
*
57+
* @param string $className
58+
* @return ItemResolverInterface
59+
*/
60+
private function getItemResolverInstance(string $className): ItemResolverInterface
61+
{
62+
if (!isset($this->itemResolversInstances[$className])) {
63+
$this->itemResolversInstances[$className] = ObjectManager::getInstance()->get($className);
64+
}
65+
66+
return $this->itemResolversInstances[$className];
67+
}
68+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Model\Product\Configuration\Item;
9+
10+
use Magento\Catalog\Api\Data\ProductInterface;
11+
12+
/**
13+
* Resolves the product from a configured item.
14+
*
15+
* @api
16+
*/
17+
interface ItemResolverInterface
18+
{
19+
/**
20+
* Get the final product from a configured item by product type and selection.
21+
*
22+
* @param ItemInterface $item
23+
* @return ProductInterface
24+
*/
25+
public function getFinalProduct(ItemInterface $item): ProductInterface;
26+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd">
11+
<!--Actions to delete category-->
12+
<actionGroup name="DeleteProductAttribute">
13+
<arguments>
14+
<argument name="productAttribute"/>
15+
</arguments>
16+
<amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="goToProductAttributesGridPage"/>
17+
<waitForPageLoad time="30" stepKey="waitForProductAttributesGridPageLoad"/>
18+
<click selector="{{AdminProductAttributeGridSection.resetFilter}}" stepKey="resetFilter"/>
19+
<fillField selector="{{AdminProductAttributeGridSection.gridFilterFrontEndLabel}}"
20+
userInput="{{productAttribute.default_label}}" stepKey="fillAttributeDefaultLabelInput"/>
21+
<click selector="{{AdminProductAttributeGridSection.search}}" stepKey="searchForAttribute"/>
22+
<click selector="{{AdminProductAttributeGridSection.firstRow}}" stepKey="clickFirstRow"/>
23+
<waitForPageLoad time="30" stepKey="waitForPageLoad"/>
24+
<click selector="{{AdminProductAttributeEditSection.deleteAttribute}}" stepKey="deleteProductAttribute"/>
25+
<waitForElementVisible selector="{{AdminConfirmationModalSection.message}}" stepKey="waitingForWarningModal"/>
26+
<click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmStoreDelete"/>
27+
</actionGroup>
28+
</actionGroups>

app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,17 @@
4848
<click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickSaveProduct"/>
4949
<see selector="{{AdminProductMessagesSection.successMessage}}" userInput="You saved the product." stepKey="seeSaveConfirmation"/>
5050
</actionGroup>
51+
52+
<!--Upload image for product-->
53+
<actionGroup name="addProductImage">
54+
<arguments>
55+
<argument name="image" defaultValue="ProductImage"/>
56+
</arguments>
57+
<conditionalClick selector="{{AdminProductImagesSection.productImagesToggle}}" dependentSelector="{{AdminProductImagesSection.imageUploadButton}}" visible="false" stepKey="openProductImagesSection"/>
58+
<waitForPageLoad time="30" stepKey="waitForPageRefresh"/>
59+
<waitForElementVisible selector="{{AdminProductImagesSection.imageUploadButton}}" stepKey="seeImageSectionIsReady"/>
60+
<attachFile selector="{{AdminProductImagesSection.imageFileUpload}}" userInput="{{image.file}}" stepKey="uploadFile"/>
61+
<waitForElementNotVisible selector="{{AdminProductImagesSection.uploadProgressBar}}" stepKey="waitForUpload"/>
62+
<waitForElementVisible selector="{{AdminProductImagesSection.imageFile(image.fileName)}}" stepKey="waitForThumbnail"/>
63+
</actionGroup>
5164
</actionGroups>

app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@
2929
<waitForElementNotVisible selector="{{AdminProductGridSection.loadingMask}}" stepKey="waitForFilteredGridLoad" time="30"/>
3030
</actionGroup>
3131

32+
<!--Filter the product grid by the SKU string -->
33+
<actionGroup name="filterProductGridBySku2">
34+
<arguments>
35+
<argument name="sku" type="string"/>
36+
</arguments>
37+
<conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/>
38+
<click selector="{{AdminProductGridFilterSection.filters}}" stepKey="openProductFilters"/>
39+
<fillField selector="{{AdminProductGridFilterSection.skuFilter}}" userInput="{{sku}}" stepKey="fillProductSkuFilter"/>
40+
<click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="clickApplyFilters"/>
41+
<waitForElementNotVisible selector="{{AdminProductGridSection.loadingMask}}" stepKey="waitForFilteredGridLoad" time="30"/>
42+
</actionGroup>
43+
3244
<!--Delete a product by filtering grid and using delete action-->
3345
<actionGroup name="deleteProductUsingProductGrid">
3446
<arguments>

app/code/Magento/Catalog/Test/Mftf/ActionGroup/ProductsOnAdminActionGroup.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,22 @@
2525
<waitForElementVisible selector="{{AdminProductGridConfirmActionSection.title}}" stepKey="waitForConfirmModal"/>
2626
<click selector="{{AdminProductGridConfirmActionSection.ok}}" stepKey="clickOkInConfirmation"/>
2727
</actionGroup>
28+
29+
<actionGroup name="DeleteAllProductsOnProductsGridPageFilteredByName">
30+
<arguments>
31+
<argument name="product"/>
32+
</arguments>
33+
<amOnPage url="{{AdminProductIndexPage.url}}" stepKey="openProductsGridPage"/>
34+
<waitForPageLoad stepKey="waitForPageLoad"/>
35+
<click selector="{{AdminProductGridFilterSection.filters}}" stepKey="clickOnFiltersButton"/>
36+
<conditionalClick selector="{{AdminProductGridFilterSection.clearAll}}" dependentSelector="{{AdminProductGridFilterSection.clearAll}}" visible="true" stepKey="clearFilters"/>
37+
<fillField selector="{{AdminProductGridFilterSection.name}}" userInput="{{product.name}}" stepKey="fillNameFieldInFilter"/>
38+
<click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="applyFilters"/>
39+
<click selector="{{AdminProductGridSection.multicheckDropdown}}" stepKey="clickMulticheckDropDown"/>
40+
<click selector="{{AdminProductGridSection.multicheckOption('Select All')}}" stepKey="selectAllFilteredProducts"/>
41+
<click selector="{{AdminProductGridActionSection.actionsSelectBox}}" stepKey="openActionsSelectBox"/>
42+
<click selector="{{AdminProductGridActionSection.deleteOptionInActionsSelectBox}}" stepKey="clickDeleteAction"/>
43+
<waitForElementVisible selector="{{AdminProductGridConfirmActionSection.title}}" stepKey="waitForConfirmModal"/>
44+
<click selector="{{AdminProductGridConfirmActionSection.ok}}" stepKey="clickOkInConfirmation"/>
45+
</actionGroup>
2846
</actionGroups>

app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,24 @@
9494
<data key="file">magento-logo.png</data>
9595
<data key="fileName">magento-logo</data>
9696
</entity>
97+
<entity name="MagentoLogo" type="image">
98+
<data key="title" unique="suffix">MagentoLogo</data>
99+
<data key="price">1.00</data>
100+
<data key="file_type">Upload File</data>
101+
<data key="shareable">Yes</data>
102+
<data key="file">magento-logo.png</data>
103+
<data key="filename">magento-logo</data>
104+
<data key="file_extension">png</data>
105+
</entity>
106+
<entity name="TestImageNew" type="image">
107+
<data key="title" unique="suffix">magento-again</data>
108+
<data key="price">1.00</data>
109+
<data key="file_type">Upload File</data>
110+
<data key="shareable">Yes</data>
111+
<data key="file">magento-again.jpg</data>
112+
<data key="filename">magento-again</data>
113+
<data key="file_extension">jpg</data>
114+
</entity>
97115
<entity name="productWithDescription" type="product">
98116
<data key="sku" unique="suffix">testProductWithDescriptionSku</data>
99117
<data key="type_id">simple</data>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd">
11+
<page name="AdminCategoryProductAttributeEditPage" url="catalog/product_attribute/edit/" area="admin" module="Magento_Catalog">
12+
<section name="AdminProductAttributeEditSection"/>
13+
<section name="AdminConfirmationModalSection"/>
14+
</page>
15+
</pages>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd">
11+
<section name="AdminProductAttributeEditSection">
12+
<element name="deleteAttribute" type="button" selector="#delete" timeout="30"/>
13+
</section>
14+
</sections>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<element name="applyFilters" type="button" selector="button[data-action='grid-filter-apply']" timeout="30"/>
1818
<element name="newFromDateFilter" type="input" selector="input.admin__control-text[name='news_from_date[from]']"/>
1919
<element name="skuFilter" type="input" selector="input.admin__control-text[name='sku']"/>
20+
<element name="name" type="input" selector="input.admin__control-text[name='name']"/>
2021
<element name="viewBookmark" type="button" selector="//div[contains(@class, 'admin__data-grid-action-bookmarks')]/ul/li/div/a[text() = '{{label}}']" parameterized="true" timeout="30"/>
2122
<element name="viewDropdown" type="button" selector=".admin__data-grid-action-bookmarks button.admin__action-dropdown"/>
2223
</section>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@
2525
<element name="bulkActionOption" type="button" selector="//div[contains(@class,'admin__data-grid-header-row') and contains(@class, 'row')]//div[contains(@class, 'action-select-wrap')]//ul/li/span[text() = '{{label}}']" parameterized="true"/>
2626
<element name="productGridNameProduct" type="input" selector="//tbody//tr//td//div[contains(., '{{var1}}')]" parameterized="true" timeout="30"/>
2727
<element name="adminImgGridThumbnail" type="text" selector="img.admin__control-thumbnail[src*='/{{var1}}']" parameterized="true"/>
28+
<element name="selectRowBasedOnName" type="input" selector="//td/div[text()='{{var1}}']" parameterized="true"/>
2829
</section>
2930
</sections>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<element name="QtyInput" type="button" selector="input.input-text.qty"/>
1313
<element name="AddToCartBtn" type="button" selector="button.action.tocart.primary"/>
1414
<element name="SuccessMsg" type="button" selector="div.message-success"/>
15-
<element name="AddToWishlist" type="button" selector="//a[@class='action towishlist']" timeout="30"/>
15+
<element name="addToWishlist" type="button" selector="//a[@class='action towishlist']" timeout="30"/>
1616
<element name="addToCartButtonTitleIsAdding" type="text" selector="//button/span[text()='Adding...']"/>
1717
<element name="addToCartButtonTitleIsAdded" type="text" selector="//button/span[text()='Added']"/>
1818
<element name="addToCartButtonTitleIsAddToCart" type="text" selector="//button/span[text()='Add to Cart']"/>

app/code/Magento/Catalog/Test/Unit/Block/Product/ImageBuilderTest.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,8 @@ public function testCreateWithSimpleProduct($data, $expected)
303303
$imageId = 'test_image_id';
304304

305305
$productMock = $this->createMock(\Magento\Catalog\Model\Product::class);
306-
$simpleOptionMock = $this->createMock(\Magento\Wishlist\Model\Item\Option::class);
307306
$simpleProductMock = $this->createMock(\Magento\Catalog\Model\Product::class);
308307

309-
$productMock->expects($this->once())->method('getOptionById')
310-
->with('simple_product')->willReturn($simpleOptionMock);
311-
312-
$simpleOptionMock->expects($this->once())->method('getProduct')->willReturn($simpleProductMock);
313-
314308
$helperMock = $this->createMock(\Magento\Catalog\Helper\Image::class);
315309
$helperMock->expects($this->once())
316310
->method('init')

app/code/Magento/Catalog/etc/di.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
<preference for="Magento\Catalog\Api\Data\ProductRender\FormattedPriceInfoInterface" type="Magento\Catalog\Model\ProductRender\FormattedPriceInfo" />
7171
<preference for="Magento\Framework\Indexer\BatchProviderInterface" type="Magento\Framework\Indexer\BatchProvider" />
7272
<preference for="Magento\Catalog\Model\Indexer\Product\Price\UpdateIndexInterface" type="Magento\Catalog\Model\Indexer\Product\Price\InvalidateIndex" />
73+
<preference for="Magento\Catalog\Model\Product\Configuration\Item\ItemResolverInterface" type="Magento\Catalog\Model\Product\Configuration\Item\ItemResolverComposite" />
7374
<type name="Magento\Customer\Model\ResourceModel\Visitor">
7475
<plugin name="catalogLog" type="Magento\Catalog\Model\Plugin\Log" />
7576
</type>

app/code/Magento/Checkout/Block/Cart/Item/Renderer.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use Magento\Framework\View\Element\AbstractBlock;
1212
use Magento\Framework\View\Element\Message\InterpretationStrategyInterface;
1313
use Magento\Quote\Model\Quote\Item\AbstractItem;
14+
use Magento\Framework\App\ObjectManager;
15+
use Magento\Catalog\Model\Product\Configuration\Item\ItemResolverInterface;
1416

1517
/**
1618
* Shopping cart item render block
@@ -91,6 +93,11 @@ class Renderer extends \Magento\Framework\View\Element\Template implements
9193
*/
9294
private $messageInterpretationStrategy;
9395

96+
/**
97+
* @var ItemResolverInterface
98+
*/
99+
private $itemResolver;
100+
94101
/**
95102
* @param \Magento\Framework\View\Element\Template\Context $context
96103
* @param \Magento\Catalog\Helper\Product\Configuration $productConfig
@@ -102,6 +109,7 @@ class Renderer extends \Magento\Framework\View\Element\Template implements
102109
* @param \Magento\Framework\Module\Manager $moduleManager
103110
* @param InterpretationStrategyInterface $messageInterpretationStrategy
104111
* @param array $data
112+
* @param ItemResolverInterface|null $itemResolver
105113
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
106114
* @codeCoverageIgnore
107115
*/
@@ -115,7 +123,8 @@ public function __construct(
115123
PriceCurrencyInterface $priceCurrency,
116124
\Magento\Framework\Module\Manager $moduleManager,
117125
InterpretationStrategyInterface $messageInterpretationStrategy,
118-
array $data = []
126+
array $data = [],
127+
ItemResolverInterface $itemResolver = null
119128
) {
120129
$this->priceCurrency = $priceCurrency;
121130
$this->imageBuilder = $imageBuilder;
@@ -127,6 +136,7 @@ public function __construct(
127136
$this->_isScopePrivate = true;
128137
$this->moduleManager = $moduleManager;
129138
$this->messageInterpretationStrategy = $messageInterpretationStrategy;
139+
$this->itemResolver = $itemResolver ?: ObjectManager::getInstance()->get(ItemResolverInterface::class);
130140
}
131141

132142
/**
@@ -172,7 +182,7 @@ public function getProduct()
172182
*/
173183
public function getProductForThumbnail()
174184
{
175-
return $this->getProduct();
185+
return $this->itemResolver->getFinalProduct($this->getItem());
176186
}
177187

178188
/**

0 commit comments

Comments
 (0)