Skip to content

Commit d461705

Browse files
committed
Merge branch '2.4-develop' of https://github.com/magento-commerce/magento2ce into ACP2E-1937
2 parents cc60040 + 74b1871 commit d461705

File tree

37 files changed

+1845
-695
lines changed

37 files changed

+1845
-695
lines changed

app/code/Magento/AwsS3/Test/Mftf/Test/AdminAwsS3SyncZeroByteFilesTest.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@
4444
<!-- Disable AWS S3 Remote Storage -->
4545
<magentoCLI command="setup:config:set {{RemoteStorageAwsS3ConfigData.disable_options}}" stepKey="disableRemoteStorage"/>
4646
</after>
47-
<magentoCLI command="remote-storage:sync" timeout="120" stepKey="syncRemoteStorage"/>
48-
<assertEquals stepKey="assertConfigTest">
49-
<expectedResult type="string">Uploading media files to remote storage.\n- empty.jpg\nEnd of upload.</expectedResult>
47+
<magentoCLI command="remote-storage:sync" timeout="200" stepKey="syncRemoteStorage"/>
48+
<comment userInput="checking remote-storage:sync" stepKey="assertConfigTest"/>
49+
<assertStringContainsString stepKey="checkingRemoteStorageSync">
50+
<expectedResult type="string">Uploading media files to remote storage</expectedResult>
5051
<actualResult type="variable">$syncRemoteStorage</actualResult>
51-
</assertEquals>
52-
52+
</assertStringContainsString>
5353
</test>
5454
</tests>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
/**
3+
* Copyright 2023 Adobe
4+
* All Rights Reserved.
5+
*
6+
* NOTICE: All information contained herein is, and remains
7+
* the property of Adobe and its suppliers, if any. The intellectual
8+
* and technical concepts contained herein are proprietary to Adobe
9+
* and its suppliers and are protected by all applicable intellectual
10+
* property laws, including trade secret and copyright laws.
11+
* Dissemination of this information or reproduction of this material
12+
* is strictly forbidden unless prior written permission is obtained from
13+
* Adobe.
14+
*/
15+
declare(strict_types=1);
16+
17+
namespace Magento\Catalog\Test\Fixture;
18+
19+
use Magento\CatalogInventory\Api\StockRegistryInterface;
20+
use Magento\Framework\DataObject;
21+
use Magento\Framework\DataObjectFactory;
22+
use Magento\TestFramework\Fixture\Api\DataMerger;
23+
use Magento\TestFramework\Fixture\DataFixtureInterface;
24+
25+
class ProductStock implements DataFixtureInterface
26+
{
27+
private const DEFAULT_DATA = [
28+
'prod_id' => null,
29+
'prod_qty' => 1
30+
];
31+
32+
/**
33+
* @var DataObjectFactory
34+
*/
35+
protected DataObjectFactory $dataObjectFactory;
36+
37+
/**
38+
* @var StockRegistryInterface
39+
*/
40+
protected StockRegistryInterface $stockRegistry;
41+
42+
/**
43+
* @var DataMerger
44+
*/
45+
protected DataMerger $dataMerger;
46+
47+
/**
48+
* @param DataObjectFactory $dataObjectFactory
49+
* @param StockRegistryInterface $stockRegistry
50+
* @param DataMerger $dataMerger
51+
*/
52+
public function __construct(
53+
DataObjectFactory $dataObjectFactory,
54+
StockRegistryInterface $stockRegistry,
55+
DataMerger $dataMerger
56+
) {
57+
$this->dataObjectFactory = $dataObjectFactory;
58+
$this->stockRegistry = $stockRegistry;
59+
$this->dataMerger = $dataMerger;
60+
}
61+
62+
/**
63+
* {@inheritdoc}
64+
* @param array $data Parameters. Same format as ProductStock::DEFAULT_DATA
65+
*/
66+
public function apply(array $data = []): ?DataObject
67+
{
68+
$data = $this->dataMerger->merge(self::DEFAULT_DATA, $data);
69+
$stockItem = $this->stockRegistry->getStockItem($data['prod_id']);
70+
$stockItem->setData('is_in_stock', 1);
71+
$stockItem->setData('qty', 90);
72+
$stockItem->setData('manage_stock', 1);
73+
$stockItem->save();
74+
75+
return $this->dataObjectFactory->create(['data' => [$data]]);
76+
}
77+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<argument name="categoryName" type="string"/>
1717
</arguments>
1818

19+
<waitForElementVisible selector="{{StorefrontHeaderSection.NavigationCategoryByName(categoryName)}}" stepKey="waitForCatName" time="120"/>
1920
<seeElement selector="{{StorefrontHeaderSection.NavigationCategoryByName(categoryName)}}"
2021
stepKey="seeCatergoryInStoreFront"/>
2122
</actionGroup>

app/code/Magento/Catalog/Test/Mftf/Test/StorefrontCategorySidebarMobileMenuTest.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,17 @@
4242
<click selector="{{StorefrontHeaderSection.mobileMenuToggle}}" stepKey="openSideMenu"/>
4343
<waitForElementClickable selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createParentCategory.name$$)}}" stepKey="waitForCategoryMenuClickable" />
4444
<click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createParentCategory.name$$)}}" stepKey="expandCategoryMenu"/>
45-
<waitForPageLoad stepKey="waitForSearchResult"/>
45+
<waitForPageLoad stepKey="waitForSearchResult" time="60"/>
4646

4747
<!-- Assert the category expanded successfully -->
4848
<actionGroup ref="StorefrontAssertCategoryNameIsShownInMenuActionGroup" stepKey="verifySubCatMenuItemIsVisibleInTheSidebar">
4949
<argument name="categoryName" value="$$createSubCategory.name$$"/>
5050
</actionGroup>
5151

5252
<!-- Open the subcategory and assert it opened successfully -->
53+
<waitForElementClickable selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createSubCategory.name$$)}}" stepKey="waitForSubCategory" time="90"/>
5354
<click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createSubCategory.name$$)}}" stepKey="openSubCategory"/>
55+
<waitForElementVisible selector="{{StorefrontCategoryMainSection.CategoryTitle}}" stepKey="waitForCategoryName" time="90"/>
5456
<see userInput="$$createSubCategory.name$$" selector="{{StorefrontCategoryMainSection.CategoryTitle}}" stepKey="assertCategoryName"/>
5557
</test>
5658
</tests>

app/code/Magento/CatalogImportExport/Model/Import/Product.php

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
class Product extends AbstractEntity
5454
{
5555
private const COL_NAME_FORMAT = '/[\x00-\x1F\x7F]/';
56-
private const DEFAULT_GLOBAL_MULTIPLE_VALUE_SEPARATOR = ',';
5756
public const CONFIG_KEY_PRODUCT_TYPES = 'global/importexport/import_product_types';
5857

5958
/**
@@ -939,7 +938,7 @@ public function __construct(
939938
$this->_optionEntity = $data['option_entity'] ??
940939
$optionFactory->create(['data' => ['product_entity' => $this]]);
941940
$this->skuStorage = $skuStorage ?? ObjectManager::getInstance()
942-
->get(SkuStorage::class);
941+
->get(SkuStorage::class);
943942
$this->_initAttributeSets()
944943
->_initTypeModels()
945944
->_initSkus()
@@ -949,7 +948,7 @@ public function __construct(
949948
$this->productRepository = $productRepository ?? ObjectManager::getInstance()
950949
->get(ProductRepositoryInterface::class);
951950
$this->stockItemProcessor = $stockItemProcessor ?? ObjectManager::getInstance()
952-
->get(StockItemProcessorInterface::class);
951+
->get(StockItemProcessorInterface::class);
953952
}
954953

955954
/**
@@ -2837,7 +2836,7 @@ private function prepareNewSkuData($sku)
28372836
*
28382837
* @return array
28392838
*/
2840-
private function _parseAdditionalAttributes($rowData)
2839+
private function _parseAdditionalAttributes(array $rowData): array
28412840
{
28422841
if (empty($rowData['additional_attributes'])) {
28432842
return $rowData;
@@ -2847,7 +2846,7 @@ private function _parseAdditionalAttributes($rowData)
28472846
$rowData[mb_strtolower($key)] = $value;
28482847
}
28492848
} else {
2850-
$rowData = array_merge($rowData, $this->getAdditionalAttributes($rowData['additional_attributes']));
2849+
$rowData = array_merge($rowData, $this->getAdditionalAttributes($rowData));
28512850
}
28522851
return $rowData;
28532852
}
@@ -2861,14 +2860,14 @@ private function _parseAdditionalAttributes($rowData)
28612860
* codeN => valueN
28622861
* ]
28632862
*
2864-
* @param string $additionalAttributes Attributes data that will be parsed
2863+
* @param array $rowData
28652864
* @return array
28662865
*/
2867-
private function getAdditionalAttributes($additionalAttributes)
2866+
private function getAdditionalAttributes(array $rowData): array
28682867
{
28692868
return empty($this->_parameters[Import::FIELDS_ENCLOSURE])
2870-
? $this->parseAttributesWithoutWrappedValues($additionalAttributes)
2871-
: $this->parseAttributesWithWrappedValues($additionalAttributes);
2869+
? $this->parseAttributesWithoutWrappedValues($rowData['additional_attributes'], $rowData['product_type'])
2870+
: $this->parseAttributesWithWrappedValues($rowData['additional_attributes']);
28722871
}
28732872

28742873
/**
@@ -2882,9 +2881,10 @@ private function getAdditionalAttributes($additionalAttributes)
28822881
*
28832882
* @param string $attributesData Attributes data that will be parsed. It keeps data in format:
28842883
* code=value,code2=value2...,codeN=valueN
2884+
* @param string $productType
28852885
* @return array
28862886
*/
2887-
private function parseAttributesWithoutWrappedValues($attributesData)
2887+
private function parseAttributesWithoutWrappedValues(string $attributesData, string $productType): array
28882888
{
28892889
$attributeNameValuePairs = explode($this->getMultipleValueSeparator(), $attributesData);
28902890
$preparedAttributes = [];
@@ -2900,6 +2900,17 @@ private function parseAttributesWithoutWrappedValues($attributesData)
29002900
}
29012901
list($code, $value) = explode(self::PAIR_NAME_VALUE_SEPARATOR, $attributeData, 2);
29022902
$code = mb_strtolower($code);
2903+
2904+
$entityTypeModel = $this->retrieveProductTypeByName($productType);
2905+
if ($entityTypeModel) {
2906+
$attrParams = $entityTypeModel->retrieveAttributeFromCache($code);
2907+
if (!empty($attrParams) && $attrParams['type'] == 'multiselect') {
2908+
$parsedValue = $this->parseMultiselectValues($value, self::PSEUDO_MULTI_LINE_SEPARATOR);
2909+
if (count($parsedValue) > 1) {
2910+
$value = $parsedValue;
2911+
}
2912+
}
2913+
}
29032914
$preparedAttributes[$code] = $value;
29042915
}
29052916
return $preparedAttributes;
@@ -2949,10 +2960,13 @@ private function parseAttributesWithWrappedValues($attributesData)
29492960
* @return array
29502961
* @since 100.1.2
29512962
*/
2952-
public function parseMultiselectValues($values, $delimiter = self::PSEUDO_MULTI_LINE_SEPARATOR)
2963+
public function parseMultiselectValues($values, $delimiter = '')
29532964
{
29542965
if (empty($this->_parameters[Import::FIELDS_ENCLOSURE])) {
2955-
if ($this->getMultipleValueSeparator() !== self::DEFAULT_GLOBAL_MULTIPLE_VALUE_SEPARATOR) {
2966+
if (is_array($values)) {
2967+
return $values;
2968+
}
2969+
if (!$delimiter) {
29562970
$delimiter = $this->getMultipleValueSeparator();
29572971
}
29582972

app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/ValidatorTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ protected function setUp(): void
4747
$entityTypeModel->expects($this->any())->method('retrieveAttributeFromCache')->willReturn([]);
4848
$this->context = $this->createPartialMock(
4949
Product::class,
50-
['retrieveProductTypeByName', 'retrieveMessageTemplate', 'getBehavior']
50+
['retrieveProductTypeByName', 'retrieveMessageTemplate', 'getBehavior', 'getMultipleValueSeparator']
5151
);
5252
$this->context->expects($this->any())->method('retrieveProductTypeByName')->willReturn($entityTypeModel);
5353
$this->context->expects($this->any())->method('retrieveMessageTemplate')->willReturn('error message');
@@ -83,6 +83,7 @@ protected function setUp(): void
8383
*/
8484
public function testAttributeValidation($behavior, $attrParams, $rowData, $isValid, $attrCode = 'attribute_code')
8585
{
86+
$this->context->method('getMultipleValueSeparator')->willReturn(Product::PSEUDO_MULTI_LINE_SEPARATOR);
8687
$this->context->expects($this->any())->method('getBehavior')->willReturn($behavior);
8788
$result = $this->validator->isAttributeValid(
8889
$attrCode,

app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Magento\CatalogInventory\Api\StockConfigurationInterface;
2626
use Magento\CatalogInventory\Api\StockRegistryInterface;
2727
use Magento\CatalogInventory\Model\Spi\StockStateProviderInterface;
28+
use Magento\ConfigurableImportExport\Model\Import\Product\Type\Configurable;
2829
use Magento\Eav\Model\Config;
2930
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
3031
use Magento\Eav\Model\Entity\Attribute\Set;
@@ -1471,18 +1472,32 @@ public function testGetImagesFromRow($rowData, $expectedResult): void
14711472
*/
14721473
public function testParseAttributesWithoutWrappedValuesWillReturnsLowercasedAttributeCodes(): void
14731474
{
1474-
$attributesData = 'PARAM1=value1,param2=value2';
1475+
$entityTypeModel = $this->createPartialMock(
1476+
Configurable::class,
1477+
['retrieveAttributeFromCache']
1478+
);
1479+
$entityTypeModel->expects($this->exactly(2))->method('retrieveAttributeFromCache')->willReturn([
1480+
'type' => 'multiselect'
1481+
]);
1482+
$importProduct = $this->getMockBuilder(Product::class)
1483+
->disableOriginalConstructor()
1484+
->onlyMethods(['retrieveProductTypeByName'])
1485+
->getMock();
1486+
$importProduct->expects($this->exactly(2))->method('retrieveProductTypeByName')->willReturn($entityTypeModel);
1487+
1488+
$attributesData = 'PARAM1=value1,param2=value2|value3';
14751489
$preparedAttributes = $this->invokeMethod(
1476-
$this->importProduct,
1490+
$importProduct,
14771491
'parseAttributesWithoutWrappedValues',
1478-
[$attributesData]
1492+
[$attributesData, 'configurable']
14791493
);
14801494

14811495
$this->assertArrayHasKey('param1', $preparedAttributes);
14821496
$this->assertEquals('value1', $preparedAttributes['param1']);
14831497

14841498
$this->assertArrayHasKey('param2', $preparedAttributes);
1485-
$this->assertEquals('value2', $preparedAttributes['param2']);
1499+
$this->assertEquals('value2', $preparedAttributes['param2'][0]);
1500+
$this->assertEquals('value3', $preparedAttributes['param2'][1]);
14861501

14871502
$this->assertArrayNotHasKey('PARAM1', $preparedAttributes);
14881503
}
@@ -1684,7 +1699,7 @@ public function productCategoriesDataProvider()
16841699
],
16851700
'catalog_category_product',
16861701
[
1687-
[2, 5],
1702+
[2, 5],
16881703
[
16891704
[
16901705
'product_id' => 2,
@@ -2191,4 +2206,57 @@ protected function createModelMockWithErrorAggregator(
21912206

21922207
return $importProduct;
21932208
}
2209+
2210+
/**
2211+
* @dataProvider valuesDataProvider
2212+
*/
2213+
public function testParseMultiselectValues($value, $fieldSeparator, $valueSeparator)
2214+
{
2215+
$this->importProduct->setParameters(
2216+
[
2217+
Import::FIELD_FIELD_SEPARATOR => $fieldSeparator,
2218+
Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR => $valueSeparator
2219+
]
2220+
);
2221+
$this->assertEquals(explode($valueSeparator, $value), $this->importProduct->parseMultiselectValues($value));
2222+
}
2223+
2224+
/**
2225+
* @return array
2226+
*/
2227+
public function valuesDataProvider(): array
2228+
{
2229+
return [
2230+
'pipeWithCustomFieldSeparator' => [
2231+
'value' => 'L|C|D|T|H',
2232+
'fieldSeparator' => ';',
2233+
'valueSeparator' => '|'
2234+
],
2235+
'commaWithCustomFieldSeparator' => [
2236+
'value' => 'L,C,D,T,H',
2237+
'fieldSeparator' => ';',
2238+
'valueSeparator' => ','
2239+
],
2240+
'pipeWithDefaultFieldSeparator' => [
2241+
'value' => 'L|C|D|T|H',
2242+
'fieldSeparator' => ',',
2243+
'valueSeparator' => '|'
2244+
],
2245+
'commaWithDefaultFieldSeparator' => [
2246+
'value' => 'L,C,D,T,H',
2247+
'fieldSeparator' => ',',
2248+
'valueSeparator' => ','
2249+
],
2250+
'anonymousValueSeparatorWithDefaultFieldSeparator' => [
2251+
'value' => 'L+C+D+T+H',
2252+
'fieldSeparator' => ',',
2253+
'valueSeparator' => '+'
2254+
],
2255+
'anonymousValueSeparatorWithDefaultFieldSeparatorAndSingleValue' => [
2256+
'value' => 'L',
2257+
'fieldSeparator' => ',',
2258+
'valueSeparator' => '*'
2259+
]
2260+
];
2261+
}
21942262
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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="GuestVerifiesTheShipToDetailsOnStorefrontCheckoutPaymentActionGroup">
12+
<annotations>
13+
<description>Guest verifies the Shipping details on storefront checkout payment page.</description>
14+
</annotations>
15+
<arguments>
16+
<argument name="firstName" type="string" defaultValue="{{CustomerAddressSimple.firstName}}"/>
17+
<argument name="lastName" type="string" defaultValue="{{CustomerAddressSimple.lastName}}"/>
18+
<argument name="street" type="string" defaultValue="{{CustomerAddressSimple.street[0]}}"/>
19+
<argument name="city" type="string" defaultValue="{{CustomerAddressSimple.city}}"/>
20+
<argument name="state" type="string" defaultValue="{{CustomerAddressSimple.state}}"/>
21+
<argument name="postcode" type="string" defaultValue="{{CustomerAddressSimple.postcode}}"/>
22+
<argument name="telephone" type="string" defaultValue="{{CustomerAddressSimple.telephone}}"/>
23+
</arguments>
24+
<waitForText selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{firstName}}" stepKey="assertShipToFirstName" />
25+
<waitForText selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{lastName}}" stepKey="assertShipToLastName" />
26+
<waitForText selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{street}}" stepKey="assertShipToStreet" />
27+
<waitForText selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{city}}" stepKey="assertShipToCity" />
28+
<waitForText selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{state}}" stepKey="assertShipToState" />
29+
<waitForText selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{postcode}}" stepKey="assertShipToPostcode" />
30+
<waitForText selector="{{CheckoutPaymentSection.shipToInformation}}" userInput="{{telephone}}" stepKey="assertShipToTelephone" />
31+
</actionGroup>
32+
</actionGroups>
33+

0 commit comments

Comments
 (0)