forked from magento/magento2
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/MC-31023' into 2.4-develop-com-pr6
- Loading branch information
Showing
8 changed files
with
642 additions
and
0 deletions.
There are no files selected for viewing
56 changes: 56 additions & 0 deletions
56
dev/tests/integration/framework/Magento/TestFramework/Store/ExecuteInStoreContext.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\TestFramework\Store; | ||
|
||
use Magento\Store\Api\Data\StoreInterface; | ||
use Magento\Store\Model\StoreManagerInterface; | ||
|
||
/** | ||
* Execute operation in specified store | ||
*/ | ||
class ExecuteInStoreContext | ||
{ | ||
/** @var StoreManagerInterface */ | ||
private $storeManager; | ||
|
||
/** | ||
* @param StoreManagerInterface $storeManager | ||
*/ | ||
public function __construct(StoreManagerInterface $storeManager) | ||
{ | ||
$this->storeManager = $storeManager; | ||
} | ||
|
||
/** | ||
* Execute callback in store context | ||
* | ||
* @param null|string|bool|int|StoreInterface $store | ||
* @param callable $method | ||
* @param array $arguments | ||
* @return mixed | ||
*/ | ||
public function execute($store, callable $method, ...$arguments) | ||
{ | ||
$storeCode = $store instanceof StoreInterface | ||
? $store->getCode() | ||
: $this->storeManager->getStore($store)->getCode(); | ||
$currentStore = $this->storeManager->getStore(); | ||
|
||
try { | ||
if ($currentStore->getCode() !== $storeCode) { | ||
$this->storeManager->setCurrentStore($storeCode); | ||
} | ||
|
||
return $method(...array_values($arguments)); | ||
} finally { | ||
if ($currentStore->getCode() !== $storeCode) { | ||
$this->storeManager->setCurrentStore($currentStore); | ||
} | ||
} | ||
} | ||
} |
255 changes: 255 additions & 0 deletions
255
...nfigurableProduct/Block/Product/View/Type/MultiStoreConfigurableViewOnProductPageTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\ConfigurableProduct\Block\Product\View\Type; | ||
|
||
use Magento\Catalog\Api\Data\ProductInterface; | ||
use Magento\Catalog\Api\ProductRepositoryInterface; | ||
use Magento\Catalog\Model\Product\Attribute\Source\Status; | ||
use Magento\Catalog\Model\ResourceModel\Product as ProductResource; | ||
use Magento\Framework\ObjectManagerInterface; | ||
use Magento\Framework\Serialize\SerializerInterface; | ||
use Magento\Framework\View\LayoutInterface; | ||
use Magento\Store\Model\StoreManagerInterface; | ||
use Magento\TestFramework\Helper\Bootstrap; | ||
use Magento\TestFramework\Store\ExecuteInStoreContext; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
/** | ||
* Class check configurable product options displaying per stores | ||
* | ||
* @magentoDbIsolation disabled | ||
*/ | ||
class MultiStoreConfigurableViewOnProductPageTest extends TestCase | ||
{ | ||
/** @var ObjectManagerInterface */ | ||
private $objectManager; | ||
|
||
/** @var ProductRepositoryInterface */ | ||
private $productRepository; | ||
|
||
/** @var StoreManagerInterface */ | ||
private $storeManager; | ||
|
||
/** @var LayoutInterface */ | ||
private $layout; | ||
|
||
/** @var SerializerInterface */ | ||
private $serializer; | ||
|
||
/** @var ProductResource */ | ||
private $productResource; | ||
|
||
/** @var ExecuteInStoreContext */ | ||
private $executeInStoreContext; | ||
|
||
/** | ||
* @inheritdoc | ||
*/ | ||
protected function setUp() | ||
{ | ||
parent::setUp(); | ||
|
||
$this->objectManager = Bootstrap::getObjectManager(); | ||
$this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); | ||
$this->productRepository->cleanCache(); | ||
$this->storeManager = $this->objectManager->get(StoreManagerInterface::class); | ||
$this->layout = $this->objectManager->get(LayoutInterface::class); | ||
$this->serializer = $this->objectManager->get(SerializerInterface::class); | ||
$this->productResource = $this->objectManager->get(ProductResource::class); | ||
$this->executeInStoreContext = $this->objectManager->get(ExecuteInStoreContext::class); | ||
} | ||
|
||
/** | ||
* @magentoDataFixture Magento/ConfigurableProduct/_files/configurable_product_different_option_labeles_per_stores.php | ||
* | ||
* @dataProvider expectedLabelsDataProvider | ||
* | ||
* @param array $expectedStoreData | ||
* @param array $expectedSecondStoreData | ||
* @return void | ||
*/ | ||
public function testMultiStoreLabelView(array $expectedStoreData, array $expectedSecondStoreData): void | ||
{ | ||
$this->executeInStoreContext->execute('default', [$this, 'assertProductLabel'], $expectedStoreData); | ||
$this->executeInStoreContext->execute('fixturestore', [$this, 'assertProductLabel'], $expectedSecondStoreData); | ||
} | ||
|
||
/** | ||
* @return array | ||
*/ | ||
public function expectedLabelsDataProvider(): array | ||
{ | ||
return [ | ||
[ | ||
'options_first_store' => [ | ||
'simple_option_1_default_store' => [ | ||
'label' => 'Option 1 Default Store', | ||
], | ||
'simple_option_2_default_store' => [ | ||
'label' => 'Option 2 Default Store', | ||
], | ||
'simple_option_3_default_store' => [ | ||
'label' => 'Option 3 Default Store', | ||
], | ||
], | ||
'options_second_store' => [ | ||
'simple_option_1_default_store' => [ | ||
'label' => 'Option 1 Second Store', | ||
], | ||
'simple_option_2_default_store' => [ | ||
'label' => 'Option 2 Second Store', | ||
], | ||
'simple_option_3_default_store' => [ | ||
'label' => 'Option 3 Second Store', | ||
], | ||
], | ||
], | ||
]; | ||
} | ||
|
||
/** | ||
* Assert configurable product labels config | ||
* | ||
* @param $expectedStoreData | ||
* @return void | ||
*/ | ||
public function assertProductLabel($expectedStoreData): void | ||
{ | ||
$product = $this->productRepository->get('configurable', false, null, true); | ||
$config = $this->getBlockConfig($product)['attributes'] ?? null; | ||
$this->assertNotNull($config); | ||
$this->assertAttributeConfig($expectedStoreData, reset($config)); | ||
} | ||
|
||
/** | ||
* @magentoDataFixture Magento/ConfigurableProduct/_files/configurable_product_two_websites.php | ||
* | ||
* @dataProvider expectedProductDataProvider | ||
* | ||
* @param array $expectedProducts | ||
* @param array $expectedSecondStoreProducts | ||
* @return void | ||
*/ | ||
public function testMultiStoreOptionsView(array $expectedProducts, array $expectedSecondStoreProducts): void | ||
{ | ||
$this->prepareConfigurableProduct('configurable', 'fixture_second_store'); | ||
$this->executeInStoreContext->execute('default', [$this, 'assertProductConfig'], $expectedProducts); | ||
$this->executeInStoreContext->execute( | ||
'fixture_second_store', | ||
[$this, 'assertProductConfig'], | ||
$expectedSecondStoreProducts | ||
); | ||
} | ||
|
||
/** | ||
* @return array | ||
*/ | ||
public function expectedProductDataProvider(): array | ||
{ | ||
return [ | ||
[ | ||
'expected_store_products' => ['simple_option_1', 'simple_option_2'], | ||
'expected_second_store_products' => ['simple_option_2'], | ||
], | ||
]; | ||
} | ||
|
||
/** | ||
* Assert configurable product config | ||
* | ||
* @param $expectedProducts | ||
* @return void | ||
*/ | ||
public function assertProductConfig($expectedProducts): void | ||
{ | ||
$product = $this->productRepository->get('configurable', false, null, true); | ||
$config = $this->getBlockConfig($product)['index'] ?? null; | ||
$this->assertNotNull($config); | ||
$this->assertProducts($expectedProducts, $config); | ||
} | ||
|
||
/** | ||
* Prepare configurable product to test | ||
* | ||
* @param string $sku | ||
* @param string $storeCode | ||
* @return void | ||
*/ | ||
private function prepareConfigurableProduct(string $sku, string $storeCode): void | ||
{ | ||
$product = $this->productRepository->get($sku, false, null, true); | ||
$productToUpdate = $product->getTypeInstance()->getUsedProductCollection($product) | ||
->setPageSize(1)->getFirstItem(); | ||
$this->assertNotEmpty($productToUpdate->getData(), 'Configurable product does not have a child'); | ||
$this->executeInStoreContext->execute($storeCode, [$this, 'setProductDisabled'], $productToUpdate); | ||
} | ||
|
||
/** | ||
* Assert product options display per stores | ||
* | ||
* @param array $expectedProducts | ||
* @param array $config | ||
* @return void | ||
*/ | ||
private function assertProducts(array $expectedProducts, array $config): void | ||
{ | ||
$this->assertCount(count($expectedProducts), $config); | ||
$idsBySkus = $this->productResource->getProductsIdsBySkus($expectedProducts); | ||
|
||
foreach ($idsBySkus as $productId) { | ||
$this->assertArrayHasKey($productId, $config); | ||
} | ||
} | ||
|
||
/** | ||
* Set product status attribute to disabled | ||
* | ||
* @param ProductInterface $product | ||
* @param string $storeCode | ||
* @return void | ||
*/ | ||
public function setProductDisabled(ProductInterface $product): void | ||
{ | ||
$product->setStatus(Status::STATUS_DISABLED); | ||
$this->productRepository->save($product); | ||
} | ||
|
||
/** | ||
* Get block config | ||
* | ||
* @param ProductInterface $product | ||
* @return array | ||
*/ | ||
private function getBlockConfig(ProductInterface $product): array | ||
{ | ||
$block = $this->layout->createBlock(Configurable::class); | ||
$block->setProduct($product); | ||
|
||
return $this->serializer->unserialize($block->getJsonConfig()); | ||
} | ||
|
||
/** | ||
* Assert configurable product config | ||
* | ||
* @param array $expectedData | ||
* @param array $actualOptions | ||
* @return void | ||
*/ | ||
private function assertAttributeConfig(array $expectedData, array $actualOptions): void | ||
{ | ||
$skus = array_keys($expectedData); | ||
$idBySkuMap = $this->productResource->getProductsIdsBySkus($skus); | ||
array_walk($actualOptions['options'], function (&$option) { | ||
unset($option['id']); | ||
}); | ||
foreach ($expectedData as $sku => &$option) { | ||
$option['products'] = [$idBySkuMap[$sku]]; | ||
} | ||
$this->assertEquals(array_values($expectedData), $actualOptions['options']); | ||
} | ||
} |
82 changes: 82 additions & 0 deletions
82
...Magento/ConfigurableProduct/_files/configurable_attribute_different_labels_per_stores.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
use Magento\Catalog\Api\Data\ProductAttributeInterface; | ||
use Magento\Catalog\Api\ProductAttributeRepositoryInterface; | ||
use Magento\Catalog\Model\ResourceModel\Eav\Attribute; | ||
use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory; | ||
use Magento\Catalog\Setup\CategorySetup; | ||
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface; | ||
use Magento\Store\Model\Store; | ||
use Magento\TestFramework\Helper\Bootstrap; | ||
|
||
require __DIR__ . '/../../Store/_files/core_fixturestore.php'; | ||
|
||
$objectManager = Bootstrap::getObjectManager(); | ||
$defaultInstalledStoreId = $storeManager->getStore('default')->getId(); | ||
$secondStoreId = $storeManager->getStore('fixturestore')->getId(); | ||
/** @var CategorySetup $installer */ | ||
$installer = $objectManager->get(CategorySetup::class); | ||
/** @var Attribute $attribute */ | ||
$attribute = $objectManager->get(AttributeFactory::class)->create(); | ||
/** @var ProductAttributeRepositoryInterface $attributeRepository */ | ||
$attributeRepository = $objectManager->get(ProductAttributeRepositoryInterface::class); | ||
$entityType = $installer->getEntityTypeId(ProductAttributeInterface::ENTITY_TYPE_CODE); | ||
if (!$attribute->loadByCode($entityType, 'different_labels_attribute')->getAttributeId()) { | ||
$attribute->setData( | ||
[ | ||
'frontend_label' => ['Different option labels dropdown attribute'], | ||
'entity_type_id' => $entityType, | ||
'frontend_input' => 'select', | ||
'backend_type' => 'int', | ||
'is_required' => '0', | ||
'attribute_code' => 'different_labels_attribute', | ||
'is_global' => ScopedAttributeInterface::SCOPE_GLOBAL, | ||
'is_user_defined' => 1, | ||
'is_unique' => '0', | ||
'is_searchable' => '0', | ||
'is_comparable' => '0', | ||
'is_filterable' => '1', | ||
'is_filterable_in_search' => '0', | ||
'is_used_for_promo_rules' => '0', | ||
'is_html_allowed_on_front' => '1', | ||
'used_in_product_listing' => '1', | ||
'used_for_sort_by' => '0', | ||
'option' => [ | ||
'value' => [ | ||
'option_1' => [ | ||
Store::DEFAULT_STORE_ID => 'Option 1', | ||
$defaultInstalledStoreId => 'Option 1 Default Store', | ||
$secondStoreId => 'Option 1 Second Store', | ||
], | ||
'option_2' => [ | ||
Store::DEFAULT_STORE_ID => 'Option 2', | ||
$defaultInstalledStoreId => 'Option 2 Default Store', | ||
$secondStoreId => 'Option 2 Second Store', | ||
], | ||
'option_3' => [ | ||
Store::DEFAULT_STORE_ID => 'Option 3', | ||
$defaultInstalledStoreId => 'Option 3 Default Store', | ||
$secondStoreId => 'Option 3 Second Store', | ||
], | ||
], | ||
'order' => [ | ||
'option_1' => 1, | ||
'option_2' => 2, | ||
'option_3' => 3, | ||
], | ||
], | ||
] | ||
); | ||
$attributeRepository->save($attribute); | ||
$installer->addAttributeToGroup( | ||
ProductAttributeInterface::ENTITY_TYPE_CODE, | ||
'Default', | ||
'General', | ||
$attribute->getId() | ||
); | ||
} |
Oops, something went wrong.