From 42bec43486729ebd645329d90a40ec7b5fd58664 Mon Sep 17 00:00:00 2001 From: Bohdan Shevchenko <1408sheva@gmail.com> Date: Wed, 4 Nov 2020 09:52:41 +0200 Subject: [PATCH 01/14] MC-37507: Create automated test for "Invoice Sales Archive" --- ...sertNumberOfRecordsInUiGridActionGroup.xml | 20 +++++++++++++++++++ .../AdminGridHeadersSection.xml | 1 + 2 files changed, 21 insertions(+) create mode 100644 app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminAssertNumberOfRecordsInUiGridActionGroup.xml diff --git a/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminAssertNumberOfRecordsInUiGridActionGroup.xml b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminAssertNumberOfRecordsInUiGridActionGroup.xml new file mode 100644 index 0000000000000..5928833bf4794 --- /dev/null +++ b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminAssertNumberOfRecordsInUiGridActionGroup.xml @@ -0,0 +1,20 @@ + + + + + + + Validates that the Number of Records listed on the Ui grid page is present and correct. + + + + + + + diff --git a/app/code/Magento/Ui/Test/Mftf/Section/AdminGridControlsSection/AdminGridHeadersSection.xml b/app/code/Magento/Ui/Test/Mftf/Section/AdminGridControlsSection/AdminGridHeadersSection.xml index 89831359657bf..c7aa7604d7ade 100644 --- a/app/code/Magento/Ui/Test/Mftf/Section/AdminGridControlsSection/AdminGridHeadersSection.xml +++ b/app/code/Magento/Ui/Test/Mftf/Section/AdminGridControlsSection/AdminGridHeadersSection.xml @@ -11,5 +11,6 @@ + From 40fe02b46e2df4e49012c13a81e7f5b17a82f622 Mon Sep 17 00:00:00 2001 From: Serhii Bohomaz Date: Fri, 6 Nov 2020 13:39:54 +0200 Subject: [PATCH 02/14] MC-37099: Create automated test for "Update Customer Address, with Alphanumeric Zip Code" --- .../ResourceModel/AddressRepositoryTest.php | 344 +++++++++++------- 1 file changed, 211 insertions(+), 133 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php index f80d960be2942..692252ffe3206 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php @@ -3,18 +3,28 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Customer\Model\ResourceModel; use Magento\Customer\Api\AddressRepositoryInterface; use Magento\Customer\Api\CustomerRepositoryInterface; -use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Customer\Api\Data\AddressInterfaceFactory; use Magento\Customer\Api\Data\RegionInterfaceFactory; +use Magento\Customer\Model\CustomerRegistry; +use Magento\Framework\Api\DataObjectHelper; +use Magento\Framework\Api\Filter; +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\Api\SortOrder; +use Magento\Framework\Api\SortOrderBuilder; +use Magento\Framework\Config\CacheInterface; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Store\Api\Data\WebsiteInterface; -use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; /** * Class with integration tests for AddressRepository. @@ -23,7 +33,7 @@ * @SuppressWarnings(PHPMD.ExcessivePublicCount) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class AddressRepositoryTest extends \PHPUnit\Framework\TestCase +class AddressRepositoryTest extends TestCase { /** @var AddressRepositoryInterface */ private $repository; @@ -34,34 +44,41 @@ class AddressRepositoryTest extends \PHPUnit\Framework\TestCase /** @var \Magento\Customer\Model\Data\Address[] */ private $expectedAddresses; - /** @var \Magento\Customer\Api\Data\AddressInterfaceFactory */ + /** @var AddressInterfaceFactory */ private $addressFactory; - /** @var \Magento\Framework\Api\DataObjectHelper */ + /** @var DataObjectHelper */ private $dataObjectHelper; + /** @var CustomerRegistry */ private $customerRegistry; + /** @var StoreManagerInterface */ + private $storeManager; + + /** @var RegionInterfaceFactory */ + private $regionFactory; + + /** @var CustomerRepositoryInterface */ + private $customerRepository; + /** - * Set up. + * @inheritdoc */ protected function setUp(): void { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - - /* @var \Magento\Framework\Config\CacheInterface $cache */ - $cache = $this->objectManager->create(\Magento\Framework\Config\CacheInterface::class); + $this->objectManager = Bootstrap::getObjectManager(); + /* @var CacheInterface $cache */ + $cache = $this->objectManager->get(CacheInterface::class); $cache->remove('extension_attributes_config'); - - $this->repository = $this->objectManager->create(\Magento\Customer\Api\AddressRepositoryInterface::class); - $this->addressFactory = $this->objectManager->create( - \Magento\Customer\Api\Data\AddressInterfaceFactory::class - ); - $this->dataObjectHelper = $this->objectManager->create(\Magento\Framework\Api\DataObjectHelper::class); - $this->customerRegistry = $this->objectManager->get(\Magento\Customer\Model\CustomerRegistry::class); - - $regionFactory = $this->objectManager->get(RegionInterfaceFactory::class); - $region = $regionFactory->create() + $this->repository = $this->objectManager->get(AddressRepositoryInterface::class); + $this->addressFactory = $this->objectManager->get(AddressInterfaceFactory::class); + $this->dataObjectHelper = $this->objectManager->get(DataObjectHelper::class); + $this->customerRegistry = $this->objectManager->get(CustomerRegistry::class); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); + $this->regionFactory = $this->objectManager->get(RegionInterfaceFactory::class); + $this->customerRepository = $this->objectManager->get(CustomerRepositoryInterface::class); + $region = $this->regionFactory->create() ->setRegionCode('AL') ->setRegion('Alabama') ->setRegionId(1); @@ -90,12 +107,11 @@ protected function setUp(): void ->setTelephone('3234676') ->setFirstname('John') ->setLastname('Smith'); - $this->expectedAddresses = [$address, $address2]; } /** - * Tear down. + * @inheritdoc */ protected function tearDown(): void { @@ -109,8 +125,9 @@ protected function tearDown(): void * @magentoDataFixture Magento/Customer/_files/customer_address.php * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php * @magentoAppIsolation enabled + * @return void */ - public function testSaveAddressChanges() + public function testSaveAddressChanges(): void { $address = $this->repository->getById(2); @@ -132,11 +149,19 @@ public function testSaveAddressChanges() * @magentoDataFixture Magento/Customer/_files/customer_address.php * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php * @magentoAppIsolation enabled + * @return void */ - public function testSaveAddressesIdSetButNotAlreadyExisting() + public function testSaveAddressesIdSetButNotAlreadyExisting(): void { - $this->expectException(\Magento\Framework\Exception\NoSuchEntityException::class); - $this->expectExceptionMessage('No such entity with addressId = 4200'); + $message = (string)__( + 'No such entity with %fieldName = %fieldValue', + [ + 'fieldName' => 'addressId', + 'fieldValue' => 4200 + ] + ); + $this->expectException(NoSuchEntityException::class); + $this->expectExceptionMessage($message); $proposedAddress = $this->_createSecondAddress()->setId(4200); $this->repository->save($proposedAddress); @@ -149,8 +174,9 @@ public function testSaveAddressesIdSetButNotAlreadyExisting() * @magentoDataFixture Magento/Customer/_files/customer_address.php * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php * @magentoAppIsolation enabled + * @return void */ - public function testGetAddressById() + public function testGetAddressById(): void { $addressId = 2; $address = $this->repository->getById($addressId); @@ -161,11 +187,19 @@ public function testGetAddressById() * Test for method get address by id with incorrect id. * * @magentoDataFixture Magento/Customer/_files/customer.php + * @return void */ - public function testGetAddressByIdBadAddressId() + public function testGetAddressByIdBadAddressId(): void { - $this->expectException(\Magento\Framework\Exception\NoSuchEntityException::class); - $this->expectExceptionMessage('No such entity with addressId = 12345'); + $message = (string)__( + 'No such entity with %fieldName = %fieldValue', + [ + 'fieldName' => 'addressId', + 'fieldValue' => 12345 + ] + ); + $this->expectException(NoSuchEntityException::class); + $this->expectExceptionMessage($message); $this->repository->getById(12345); } @@ -176,8 +210,9 @@ public function testGetAddressByIdBadAddressId() * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_address.php * @magentoAppIsolation enabled + * @return void */ - public function testSaveNewAddress() + public function testSaveNewAddress(): void { $proposedAddress = $this->_createSecondAddress()->setCustomerId(1); @@ -204,8 +239,9 @@ public function testSaveNewAddress() * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_address.php * @magentoAppIsolation enabled + * @return void */ - public function testSaveNewAddressWithAttributes() + public function testSaveNewAddressWithAttributes(): void { $proposedAddress = $this->_createFirstAddress() ->setCustomAttribute('firstname', 'Jane') @@ -231,8 +267,9 @@ public function testSaveNewAddressWithAttributes() * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_address.php * @magentoAppIsolation enabled + * @return void */ - public function testSaveNewInvalidAddress() + public function testSaveNewInvalidAddress(): void { $address = $this->_createFirstAddress() ->setCustomAttribute('firstname', null) @@ -256,15 +293,19 @@ public function testSaveNewInvalidAddress() * * @return void */ - public function testSaveAddressesCustomerIdNotExist() + public function testSaveAddressesCustomerIdNotExist(): void { + $message = (string)__( + 'No such entity with %fieldName = %fieldValue', + [ + 'fieldName' => 'customerId', + 'fieldValue' => 4200 + ] + ); + $this->expectException(NoSuchEntityException::class); + $this->expectExceptionMessage($message); $proposedAddress = $this->_createSecondAddress()->setCustomerId(4200); - try { - $this->repository->save($proposedAddress); - $this->fail('Expected exception not thrown'); - } catch (NoSuchEntityException $nsee) { - $this->assertEquals('No such entity with customerId = 4200', $nsee->getMessage()); - } + $this->repository->save($proposedAddress); } /** @@ -272,15 +313,19 @@ public function testSaveAddressesCustomerIdNotExist() * * @return void */ - public function testSaveAddressesCustomerIdInvalid() + public function testSaveAddressesCustomerIdInvalid(): void { + $message = (string)__( + 'No such entity with %fieldName = %fieldValue', + [ + 'fieldName' => 'customerId', + 'fieldValue' => 'this_is_not_a_valid_id' + ] + ); + $this->expectException(NoSuchEntityException::class); + $this->expectExceptionMessage($message); $proposedAddress = $this->_createSecondAddress()->setCustomerId('this_is_not_a_valid_id'); - try { - $this->repository->save($proposedAddress); - $this->fail('Expected exception not thrown'); - } catch (NoSuchEntityException $nsee) { - $this->assertEquals('No such entity with customerId = this_is_not_a_valid_id', $nsee->getMessage()); - } + $this->repository->save($proposedAddress); } /** @@ -288,24 +333,26 @@ public function testSaveAddressesCustomerIdInvalid() * * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_address.php + * @return void */ - public function testDeleteAddress() + public function testDeleteAddress(): void { $addressId = 1; // See that customer already has an address with expected addressId $addressDataObject = $this->repository->getById($addressId); $this->assertEquals($addressDataObject->getId(), $addressId); - // Delete the address from the customer $this->repository->delete($addressDataObject); - - // See that address is deleted - try { - $addressDataObject = $this->repository->getById($addressId); - $this->fail("Expected NoSuchEntityException not caught"); - } catch (NoSuchEntityException $exception) { - $this->assertEquals('No such entity with addressId = 1', $exception->getMessage()); - } + $message = (string)__( + 'No such entity with %fieldName = %fieldValue', + [ + 'fieldName' => 'addressId', + 'fieldValue' => 1 + ] + ); + $this->expectException(NoSuchEntityException::class); + $this->expectExceptionMessage($message); + $this->repository->getById($addressId); } /** @@ -313,8 +360,9 @@ public function testDeleteAddress() * * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_address.php + * @return void */ - public function testDeleteAddressById() + public function testDeleteAddressById(): void { $addressId = 1; // See that customer already has an address with expected addressId @@ -323,50 +371,63 @@ public function testDeleteAddressById() // Delete the address from the customer $this->repository->deleteById($addressId); - - // See that address is deleted - try { - $addressDataObject = $this->repository->getById($addressId); - $this->fail("Expected NoSuchEntityException not caught"); - } catch (NoSuchEntityException $exception) { - $this->assertEquals('No such entity with addressId = 1', $exception->getMessage()); - } + $message = (string)__( + 'No such entity with %fieldName = %fieldValue', + [ + 'fieldName' => 'addressId', + 'fieldValue' => 1 + ] + ); + $this->expectException(NoSuchEntityException::class); + $this->expectExceptionMessage($message); + $this->repository->getById($addressId); } /** * Test delete address from customer with incorrect address id. * * @magentoDataFixture Magento/Customer/_files/customer.php + * @return void */ - public function testDeleteAddressFromCustomerBadAddressId() + public function testDeleteAddressFromCustomerBadAddressId(): void { - try { - $this->repository->deleteById(12345); - $this->fail("Expected NoSuchEntityException not caught"); - } catch (NoSuchEntityException $exception) { - $this->assertEquals('No such entity with addressId = 12345', $exception->getMessage()); - } + $message = (string)__( + 'No such entity with %fieldName = %fieldValue', + [ + 'fieldName' => 'addressId', + 'fieldValue' => 12345 + ] + ); + $this->expectException(NoSuchEntityException::class); + $this->expectExceptionMessage($message); + $this->repository->deleteById(12345); } /** * Test for searching addressed. * - * @param \Magento\Framework\Api\Filter[] $filters - * @param \Magento\Framework\Api\Filter[] $filterGroup - * @param \Magento\Framework\Api\SortOrder[] $filterOrders + * @param Filter[] $filters + * @param Filter[] $filterGroup + * @param SortOrder[] $filterOrders * @param array $expectedResult array of expected results indexed by ID * @param int $currentPage current page for search criteria * + * @return void * @dataProvider searchAddressDataProvider * * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php * @magentoAppIsolation enabled */ - public function testSearchAddresses($filters, $filterGroup, $filterOrders, $expectedResult, $currentPage) - { - /** @var \Magento\Framework\Api\SearchCriteriaBuilder $searchBuilder */ - $searchBuilder = $this->objectManager->create(\Magento\Framework\Api\SearchCriteriaBuilder::class); + public function testSearchAddresses( + $filters, + $filterGroup, + $filterOrders, + array $expectedResult, + int $currentPage + ): void { + /** @var SearchCriteriaBuilder $searchBuilder */ + $searchBuilder = $this->objectManager->create(SearchCriteriaBuilder::class); foreach ($filters as $filter) { $searchBuilder->addFilters([$filter]); } @@ -403,18 +464,18 @@ public function testSearchAddresses($filters, $filterGroup, $filterOrders, $expe * * @return array */ - public function searchAddressDataProvider() + public function searchAddressDataProvider(): array { /** - * @var \Magento\Framework\Api\FilterBuilder $filterBuilder + * @var FilterBuilder $filterBuilder */ - $filterBuilder = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Framework\Api\FilterBuilder::class); + $filterBuilder = Bootstrap::getObjectManager() + ->create(FilterBuilder::class); /** - * @var \Magento\Framework\Api\SortOrderBuilder $orderBuilder + * @var SortOrderBuilder $orderBuilder */ - $orderBuilder = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Framework\Api\SortOrderBuilder::class); + $orderBuilder = Bootstrap::getObjectManager() + ->create(SortOrderBuilder::class); return [ 'Address with postcode 75477' => [ [$filterBuilder->setField('postcode')->setValue('75477')->create()], @@ -482,13 +543,13 @@ public function searchAddressDataProvider() * Test for save addresses with restricted countries. * * @magentoDataFixture Magento/Customer/Fixtures/customer_sec_website.php + * @return void */ - public function testSaveAddressWithRestrictedCountries() + public function testSaveAddressWithRestrictedCountries(): void { - $website = $this->getWebsite('test'); - $customer = $this->getCustomer('customer.web@example.com', (int)$website->getId()); - $regionFactory = $this->objectManager->get(RegionInterfaceFactory::class); - $region = $regionFactory->create() + $website = $this->storeManager->getWebsite('test'); + $customer = $this->customerRepository->get('customer.web@example.com', (int)$website->getId()); + $region = $this->regionFactory->create() ->setRegionCode('CA') ->setRegion('California') ->setRegionId(12); @@ -513,8 +574,9 @@ public function testSaveAddressWithRestrictedCountries() * * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Customer/_files/customer_address.php + * @return void */ - public function testSaveNewAddressWithExtraSpacesInPhone() + public function testSaveNewAddressWithExtraSpacesInPhone(): void { $proposedAddress = $this->_createSecondAddress() ->setCustomerId(1) @@ -528,8 +590,9 @@ public function testSaveNewAddressWithExtraSpacesInPhone() * Scenario for customer's default shipping and billing address saving and rollback. * * @magentoDataFixture Magento/Customer/_files/customer_without_addresses.php + * @return void */ - public function testCustomerAddressRelationSynchronisation() + public function testCustomerAddressRelationSynchronisation(): void { /** * Creating new address which is default shipping and billing for existing customer. @@ -544,7 +607,7 @@ public function testCustomerAddressRelationSynchronisation() /** * Customer registry should be updated with default shipping and billing addresses. */ - $customer = $this->getCustomer('customer@example.com', 1); + $customer = $this->customerRepository->get('customer@example.com', 1); $this->assertEquals($savedAddress->getId(), $customer->getDefaultShipping()); $this->assertEquals($savedAddress->getId(), $customer->getDefaultBilling()); @@ -557,21 +620,66 @@ public function testCustomerAddressRelationSynchronisation() /** * Customer's default shipping and billing addresses should be updated. */ - $customer = $this->getCustomer('customer@example.com', 1); + $customer = $this->customerRepository->get('customer@example.com', 1); $this->assertNull($customer->getDefaultShipping()); $this->assertNull($customer->getDefaultBilling()); } + /** + * Update Customer Address, with Alphanumeric Zip Code + * + * @magentoDataFixture Magento/Customer/_files/customer_one_address.php + * @return void + */ + public function testUpdateWithAlphanumericZipCode(): void + { + $region = $this->regionFactory->create() + ->setRegionCode('PH') + ->setRegion('Pinminnoch') + ->setRegionId(1); + $websiteId = (int)$this->storeManager->getWebsite('base')->getId(); + $customer = $this->customerRepository->get('customer_one_address@test.com', $websiteId); + $defaultBillingAddress = $customer->getDefaultBilling(); + $addressData = [ + AddressInterface::FIRSTNAME => 'Doe', + AddressInterface::LASTNAME => 'Doe', + AddressInterface::MIDDLENAME => 'Middle Name', + AddressInterface::SUFFIX => '_Suffix', + AddressInterface::PREFIX => 'Prefix', + AddressInterface::COMPANY => 'Company', + AddressInterface::STREET => ['Northgate Street, 39'], + AddressInterface::CITY => 'BICKTON', + AddressInterface::COUNTRY_ID => 'GB', + AddressInterface::REGION => $region, + AddressInterface::POSTCODE => 'KA26 1PF', + AddressInterface::TELEPHONE => '999-777-111-2345', + AddressInterface::VAT_ID => '987654321' + ]; + $customerAddress = $this->repository->getById((int)$defaultBillingAddress); + foreach ($addressData as $key => $value) { + $customerAddress->setData($key, $value); + } + $savedAddress = $this->repository->save($customerAddress); + $customerData = $savedAddress->__toArray(); + foreach ($addressData as $key => $value) { + if ($key === 'region') { + $this->assertEquals('Pinminnoch', $value->getRegion()); + } else { + $this->assertEquals($value, $customerData[$key]); + } + } + } + /** * Helper function that returns an Address Data Object that matches the data from customer_address fixture * - * @return \Magento\Customer\Api\Data\AddressInterface + * @return AddressInterface */ - private function _createFirstAddress() + private function _createFirstAddress(): AddressInterface { $address = $this->addressFactory->create(); $this->dataObjectHelper->mergeDataObjects( - \Magento\Customer\Api\Data\AddressInterface::class, + AddressInterface::class, $address, $this->expectedAddresses[0] ); @@ -583,13 +691,13 @@ private function _createFirstAddress() /** * Helper function that returns an Address Data Object that matches the data from customer_two_address fixture * - * @return \Magento\Customer\Api\Data\AddressInterface + * @return AddressInterface */ - private function _createSecondAddress() + private function _createSecondAddress(): AddressInterface { $address = $this->addressFactory->create(); $this->dataObjectHelper->mergeDataObjects( - \Magento\Customer\Api\Data\AddressInterface::class, + AddressInterface::class, $address, $this->expectedAddresses[1] ); @@ -597,34 +705,4 @@ private function _createSecondAddress() $address->setRegion($this->expectedAddresses[1]->getRegion()); return $address; } - - /** - * Gets customer entity. - * - * @param string $email - * @param int $websiteId - * @return CustomerInterface - * @throws NoSuchEntityException - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function getCustomer(string $email, int $websiteId): CustomerInterface - { - /** @var CustomerRepositoryInterface $repository */ - $repository = $this->objectManager->get(CustomerRepositoryInterface::class); - return $repository->get($email, $websiteId); - } - - /** - * Gets website entity. - * - * @param string $code - * @return WebsiteInterface - * @throws NoSuchEntityException - */ - private function getWebsite(string $code): WebsiteInterface - { - /** @var WebsiteRepositoryInterface $repository */ - $repository = $this->objectManager->get(WebsiteRepositoryInterface::class); - return $repository->get($code); - } } From c287f03ffcab71b06109de6bf0ee335de05a6045 Mon Sep 17 00:00:00 2001 From: Serhii Bohomaz Date: Fri, 6 Nov 2020 16:07:21 +0200 Subject: [PATCH 03/14] MC-37099: Create automated test for "Update Customer Address, with Alphanumeric Zip Code" --- .../ResourceModel/AddressRepositoryTest.php | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php index 692252ffe3206..4aefde9bf9fdb 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php @@ -157,7 +157,7 @@ public function testSaveAddressesIdSetButNotAlreadyExisting(): void 'No such entity with %fieldName = %fieldValue', [ 'fieldName' => 'addressId', - 'fieldValue' => 4200 + 'fieldValue' => 4200, ] ); $this->expectException(NoSuchEntityException::class); @@ -195,7 +195,7 @@ public function testGetAddressByIdBadAddressId(): void 'No such entity with %fieldName = %fieldValue', [ 'fieldName' => 'addressId', - 'fieldValue' => 12345 + 'fieldValue' => 12345, ] ); $this->expectException(NoSuchEntityException::class); @@ -299,7 +299,7 @@ public function testSaveAddressesCustomerIdNotExist(): void 'No such entity with %fieldName = %fieldValue', [ 'fieldName' => 'customerId', - 'fieldValue' => 4200 + 'fieldValue' => 4200, ] ); $this->expectException(NoSuchEntityException::class); @@ -319,7 +319,7 @@ public function testSaveAddressesCustomerIdInvalid(): void 'No such entity with %fieldName = %fieldValue', [ 'fieldName' => 'customerId', - 'fieldValue' => 'this_is_not_a_valid_id' + 'fieldValue' => 'this_is_not_a_valid_id', ] ); $this->expectException(NoSuchEntityException::class); @@ -347,7 +347,7 @@ public function testDeleteAddress(): void 'No such entity with %fieldName = %fieldValue', [ 'fieldName' => 'addressId', - 'fieldValue' => 1 + 'fieldValue' => 1, ] ); $this->expectException(NoSuchEntityException::class); @@ -375,7 +375,7 @@ public function testDeleteAddressById(): void 'No such entity with %fieldName = %fieldValue', [ 'fieldName' => 'addressId', - 'fieldValue' => 1 + 'fieldValue' => 1, ] ); $this->expectException(NoSuchEntityException::class); @@ -395,7 +395,7 @@ public function testDeleteAddressFromCustomerBadAddressId(): void 'No such entity with %fieldName = %fieldValue', [ 'fieldName' => 'addressId', - 'fieldValue' => 12345 + 'fieldValue' => 12345, ] ); $this->expectException(NoSuchEntityException::class); @@ -482,7 +482,7 @@ public function searchAddressDataProvider(): array null, null, [ - ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John'], + ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John',], ], 1 ], @@ -491,7 +491,7 @@ public function searchAddressDataProvider(): array null, null, [ - ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John'], + ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John',], ], 1 ], @@ -503,8 +503,8 @@ public function searchAddressDataProvider(): array $orderBuilder->setField('city')->setDirection(SortOrder::SORT_ASC)->create(), ], [ - ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John'], - ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John'], + ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John',], + ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John',], ], 2 ], @@ -518,8 +518,8 @@ public function searchAddressDataProvider(): array $orderBuilder->setField('city')->setDirection(SortOrder::SORT_DESC)->create(), ], [ - ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John'], - ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John'], + ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John',], + ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John',], ], 2 ], @@ -531,8 +531,8 @@ public function searchAddressDataProvider(): array $orderBuilder->setField('postcode')->setDirection(SortOrder::SORT_ASC)->create(), ], [ - ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John'], - ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John'], + ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John',], + ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John',], ], 2 ], @@ -662,8 +662,8 @@ public function testUpdateWithAlphanumericZipCode(): void $savedAddress = $this->repository->save($customerAddress); $customerData = $savedAddress->__toArray(); foreach ($addressData as $key => $value) { - if ($key === 'region') { - $this->assertEquals('Pinminnoch', $value->getRegion()); + if ($key === AddressInterface::REGION) { + $this->assertEquals($customerData[$key][AddressInterface::REGION], $value->getRegion()); } else { $this->assertEquals($value, $customerData[$key]); } From a1cc18525c022361216f21917478a41e1806ac14 Mon Sep 17 00:00:00 2001 From: Serhii Bohomaz Date: Fri, 6 Nov 2020 17:18:55 +0200 Subject: [PATCH 04/14] MC-37099: Create automated test for "Update Customer Address, with Alphanumeric Zip Code" --- .../ResourceModel/AddressRepositoryTest.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php index 4aefde9bf9fdb..3e7b59500b574 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/AddressRepositoryTest.php @@ -482,7 +482,7 @@ public function searchAddressDataProvider(): array null, null, [ - ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John',], + ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John'], ], 1 ], @@ -491,7 +491,7 @@ public function searchAddressDataProvider(): array null, null, [ - ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John',], + ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John'], ], 1 ], @@ -503,8 +503,8 @@ public function searchAddressDataProvider(): array $orderBuilder->setField('city')->setDirection(SortOrder::SORT_ASC)->create(), ], [ - ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John',], - ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John',], + ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John'], + ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John'], ], 2 ], @@ -518,8 +518,8 @@ public function searchAddressDataProvider(): array $orderBuilder->setField('city')->setDirection(SortOrder::SORT_DESC)->create(), ], [ - ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John',], - ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John',], + ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John'], + ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John'], ], 2 ], @@ -531,8 +531,8 @@ public function searchAddressDataProvider(): array $orderBuilder->setField('postcode')->setDirection(SortOrder::SORT_ASC)->create(), ], [ - ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John',], - ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John',], + ['id' => 2, 'city' => 'CityX', 'postcode' => 47676, 'firstname' => 'John'], + ['id' => 1, 'city' => 'CityM', 'postcode' => 75477, 'firstname' => 'John'], ], 2 ], @@ -562,7 +562,7 @@ public function testSaveAddressWithRestrictedCountries(): void 'country_id' => 'US', 'region' => $region, 'postcode' => 90230, - 'telephone' => '555655431' + 'telephone' => '555655431', ]; $address = $this->addressFactory->create(['data' => $addressData]); $saved = $this->repository->save($address); @@ -653,7 +653,7 @@ public function testUpdateWithAlphanumericZipCode(): void AddressInterface::REGION => $region, AddressInterface::POSTCODE => 'KA26 1PF', AddressInterface::TELEPHONE => '999-777-111-2345', - AddressInterface::VAT_ID => '987654321' + AddressInterface::VAT_ID => '987654321', ]; $customerAddress = $this->repository->getById((int)$defaultBillingAddress); foreach ($addressData as $key => $value) { From 537fc27f50be999897602bf34d2db6efd3d93856 Mon Sep 17 00:00:00 2001 From: Bohdan Shevchenko <1408sheva@gmail.com> Date: Tue, 10 Nov 2020 13:56:17 +0200 Subject: [PATCH 05/14] MC-38960: Fix and unskip test for "Admin should be able to create a Date product attribute" --- .../CreateProductAttributeEntityDateTest.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest/CreateProductAttributeEntityDateTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest/CreateProductAttributeEntityDateTest.xml index 26ff1bc45be9d..d1f7adb8a902c 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest/CreateProductAttributeEntityDateTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest/CreateProductAttributeEntityDateTest.xml @@ -16,9 +16,6 @@ - - - @@ -35,8 +32,9 @@ - + + @@ -57,7 +55,7 @@ - + From 9fb7eb2fefc4d1ad4e13dc2078b71ffc271d20f0 Mon Sep 17 00:00:00 2001 From: engcom-Echo Date: Tue, 10 Nov 2020 16:00:31 +0200 Subject: [PATCH 06/14] MC-38105: Unable to set native session handler that is different from the one define in php.ini --- .../Framework/Session/SessionManagerTest.php | 40 ++++++++++++++----- .../Framework/Session/SessionManager.php | 4 +- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php index d35d875ff8006..21321b49f2610 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php @@ -115,6 +115,9 @@ class SessionManagerTest extends \PHPUnit\Framework\TestCase */ private $appState; + /** + * @inheritdoc + */ protected function setUp(): void { $this->sessionName = 'frontEndSession'; @@ -250,8 +253,6 @@ public function testIsValidForHost() $this->model->destroy(); } - /** - */ public function testStartAreaNotSet() { $this->expectException(\Magento\Framework\Exception\SessionException::class); @@ -283,17 +284,23 @@ public function testStartAreaNotSet() $this->model->start(); } - public function testConstructor() + /** + * @param string $saveMethod + * @dataProvider dataConstructor + * + * @return void + */ + public function testConstructor(string $saveMethod): void { global $mockPHPFunctions; $mockPHPFunctions = true; $deploymentConfigMock = $this->createMock(DeploymentConfig::class); $deploymentConfigMock->method('get') - ->willReturnCallback(function ($configPath) { + ->willReturnCallback(function ($configPath) use ($saveMethod) { switch ($configPath) { case Config::PARAM_SESSION_SAVE_METHOD: - return 'db'; + return $saveMethod; case Config::PARAM_SESSION_CACHE_LIMITER: return 'private_no_expire'; case Config::PARAM_SESSION_SAVE_PATH: @@ -313,22 +320,35 @@ public function testConstructor() 'sessionConfig' => $sessionConfig, ] ); - $this->assertEquals('db', $sessionConfig->getOption('session.save_handler')); + $this->assertEquals($saveMethod, $sessionConfig->getOption('session.save_handler')); $this->assertEquals('private_no_expire', $sessionConfig->getOption('session.cache_limiter')); $this->assertEquals('explicit_save_path', $sessionConfig->getOption('session.save_path')); $this->assertArrayHasKey('session.use_only_cookies', self::$isIniSetInvoked); $this->assertEquals('1', self::$isIniSetInvoked['session.use_only_cookies']); foreach ($sessionConfig->getOptions() as $option => $value) { - if ($option=='session.save_handler') { - $this->assertArrayNotHasKey('session.save_handler', self::$isIniSetInvoked); + if ($option == 'session.save_handler' && $value == 'user') { + $this->assertArrayNotHasKey('session.save_handler', self::$isIniSetInvoked); } else { - $this->assertArrayHasKey($option, self::$isIniSetInvoked); - $this->assertEquals($value, self::$isIniSetInvoked[$option]); + $this->assertArrayHasKey($option, self::$isIniSetInvoked); + $this->assertEquals($value, self::$isIniSetInvoked[$option]); } } $this->assertTrue(self::$isSessionSetSaveHandlerInvoked); } + /** + * @return array + */ + public function dataConstructor(): array + { + return [ + [Config::PARAM_SESSION_SAVE_METHOD =>'db'], + [Config::PARAM_SESSION_SAVE_METHOD =>'redis'], + [Config::PARAM_SESSION_SAVE_METHOD =>'memcached'], + [Config::PARAM_SESSION_SAVE_METHOD =>'user'], + ]; + } + private function initializeModel(): void { $this->model = $this->objectManager->create( diff --git a/lib/internal/Magento/Framework/Session/SessionManager.php b/lib/internal/Magento/Framework/Session/SessionManager.php index 7e43a9f2d99c0..039caf202e60e 100644 --- a/lib/internal/Magento/Framework/Session/SessionManager.php +++ b/lib/internal/Magento/Framework/Session/SessionManager.php @@ -619,7 +619,9 @@ private function initIniOptions() } foreach ($this->sessionConfig->getOptions() as $option => $value) { - if ($option=='session.save_handler') { + // It is now explicitly forbidden to set the module name to "user". + // Formerly, this has been silently ignored. + if ($option === 'session.save_handler' && $value === 'user') { continue; } else { $result = ini_set($option, $value); From 41c17e7ed402f9aebda96d284e5a62bd7f72f663 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha Date: Wed, 11 Nov 2020 12:59:32 +0200 Subject: [PATCH 07/14] MC-37901: Create automated test for "Widgets with different themes is presented in grid/filter" --- .../Block/Adminhtml/Widget/InstanceTest.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/InstanceTest.php b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/InstanceTest.php index 57d4322ded9a3..9088dbfea6f85 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/InstanceTest.php +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/InstanceTest.php @@ -118,13 +118,23 @@ public function gridFiltersDataProvider(): array 'filter' => base64_encode('sort_order=1'), ], 'expected_widgets' => [ - 'recently compared products' + 'recently compared products', + ], + ], + 'filter_by_title_and_luma_theme' => [ + 'filter' => [ + 'filter' => base64_encode( + 'title=cms page widget title&theme_id=' . $this->loadThemeIdByCode('Magento/luma') + ), + ], + 'expected_widgets' => [ + 'cms page widget title', ], ], - 'filter_by_multiple_filters' => [ + 'filter_by_title_and_blank_theme' => [ 'filter' => [ 'filter' => base64_encode( - 'type=Magento%5CCatalog%5CBlock%5CWidget%5CRecentlyCompared&sort_order=1' + 'title=recently compared products&theme_id=' . $this->loadThemeIdByCode('Magento/blank') ), ], 'expected_widgets' => [ @@ -270,7 +280,7 @@ private function assertWidgets($expectedWidgets, AbstractCollection $collection) $this->assertCount(count($expectedWidgets), $collection); foreach ($expectedWidgets as $widgetTitle) { $item = $collection->getItemByColumnValue('title', $widgetTitle); - $this->assertNotNull($item); + $this->assertNotNull($item, sprintf('Expected widget %s is not present in grid', $widgetTitle)); } } From b5d053387bff1a53efebec96cf1afc7fb7bf5c25 Mon Sep 17 00:00:00 2001 From: SmVladyslav Date: Thu, 12 Nov 2020 11:33:49 +0200 Subject: [PATCH 08/14] MC-38460: Setting custom price on bundle product causes wrong prices on attached simple products when reordering. --- .../Quote/Model/Quote/Item/Processor.php | 5 +- .../Model/Sales/AdminOrder/ReorderTest.php | 89 +++++++++++++++++++ .../order_item_with_bundle_and_options.php | 10 ++- .../Model/Sales/AdminOrder/ReorderTest.php | 89 +++++++++++++++++++ ...der_item_with_configurable_and_options.php | 18 +++- 5 files changed, 204 insertions(+), 7 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/Model/Sales/AdminOrder/ReorderTest.php create mode 100644 dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Sales/AdminOrder/ReorderTest.php diff --git a/app/code/Magento/Quote/Model/Quote/Item/Processor.php b/app/code/Magento/Quote/Model/Quote/Item/Processor.php index c6bef1cc80bfb..477a6f2254d52 100644 --- a/app/code/Magento/Quote/Model/Quote/Item/Processor.php +++ b/app/code/Magento/Quote/Model/Quote/Item/Processor.php @@ -96,11 +96,12 @@ public function prepare(Item $item, DataObject $request, Product $candidate): vo } $item->addQty($candidate->getCartQty()); - $customPrice = $request->getCustomPrice(); if (!$item->getParentItem() || $item->getParentItem()->isChildrenCalculated()) { $item->setPrice($candidate->getFinalPrice()); } - if (!empty($customPrice)) { + + $customPrice = $request->getCustomPrice(); + if (!empty($customPrice) && !$candidate->getParentProductId()) { $item->setCustomPrice($customPrice); $item->setOriginalCustomPrice($customPrice); } diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Sales/AdminOrder/ReorderTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Sales/AdminOrder/ReorderTest.php new file mode 100644 index 0000000000000..6ca5ec22f5e14 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Sales/AdminOrder/ReorderTest.php @@ -0,0 +1,89 @@ +objectManager = Bootstrap::getObjectManager(); + $this->model =$this->objectManager->get(Create::class); + } + + /** + * Check Custom Price after reordering with Bundle product. + * + * @return void + * @magentoDataFixture Magento/Bundle/_files/order_item_with_bundle_and_options.php + */ + public function testReorderBundleProductWithCustomPrice(): void + { + $customPrice = 300; + /** @var $order Order */ + $order = $this->objectManager->create(Order::class); + $order->loadByIncrementId('100000001'); + $this->model->initFromOrder($order); + + /** @var QuoteItem[] $quoteItems */ + $quoteItems = $this->model->getQuote()->getAllItems(); + $firstQuoteItem = array_shift($quoteItems); + self::assertNull($firstQuoteItem->getParentItemId()); + self::assertEquals($customPrice, (int)$firstQuoteItem->getCustomPrice()); + foreach ($quoteItems as $quoteItem) { + self::assertEquals($firstQuoteItem->getId(), $quoteItem->getParentItemId()); + self::assertEquals(0, (int)$quoteItem->getCustomPrice()); + } + + $shippingMethod = 'freeshipping_freeshipping'; + /** @var Rate $rate */ + $rate = $this->objectManager->create(Rate::class); + $rate->setCode($shippingMethod); + $this->model->getQuote()->getShippingAddress()->addShippingRate($rate); + $this->model->setPaymentData(['method' => 'checkmo']); + $this->model->setIsValidate(true)->importPostData(['shipping_method' => $shippingMethod]); + $newOrder = $this->model->createOrder(); + + /** @var OrderItem[] $orderItems */ + $orderItems = $newOrder->getAllItems(); + $firstOrderItem = array_shift($orderItems); + self::assertNull($firstOrderItem->getParentItemId()); + self::assertEquals($customPrice, (int)$firstOrderItem->getPrice()); + foreach ($orderItems as $orderItem) { + self::assertEquals($firstOrderItem->getId(), $orderItem->getParentItemId()); + self::assertEquals(0, (int)$orderItem->getPrice()); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_item_with_bundle_and_options.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_item_with_bundle_and_options.php index ae85671a684d8..e20bf232c70e1 100644 --- a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_item_with_bundle_and_options.php +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_item_with_bundle_and_options.php @@ -48,6 +48,7 @@ 'bundle_option' => $bundleOptions, 'bundle_option_qty' => $bundleOptionsQty, 'qty' => 1, + 'custom_price' => 300, ]; /** @var \Magento\Sales\Model\Order\Item $orderItem */ @@ -58,7 +59,14 @@ $orderItem->setPrice($product->getPrice()); $orderItem->setRowTotal($product->getPrice()); $orderItem->setProductType($product->getTypeId()); -$orderItem->setProductOptions(['info_buyRequest' => $requestInfo]); +$orderItem->setProductOptions([ + 'info_buyRequest' => $requestInfo, + 'bundle_options' => [ + [ + 'value' => [['title' => $product->getName()]] + ] + ] +]); /** @var \Magento\Sales\Model\Order $order */ $order = $objectManager->create(\Magento\Sales\Model\Order::class); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Sales/AdminOrder/ReorderTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Sales/AdminOrder/ReorderTest.php new file mode 100644 index 0000000000000..9a02830ad74cf --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Sales/AdminOrder/ReorderTest.php @@ -0,0 +1,89 @@ +objectManager = Bootstrap::getObjectManager(); + $this->model =$this->objectManager->get(Create::class); + } + + /** + * Check Custom Price after reordering with Configurable product. + * + * @return void + * @magentoDataFixture Magento/ConfigurableProduct/_files/order_item_with_configurable_and_options.php + */ + public function testReorderConfigurableProductWithCustomPrice(): void + { + $customPrice = 300; + /** @var $order Order */ + $order = $this->objectManager->create(Order::class); + $order->loadByIncrementId('100000001'); + $this->model->initFromOrder($order); + + /** @var QuoteItem[] $quoteItems */ + $quoteItems = $this->model->getQuote()->getAllItems(); + $firstQuoteItem = array_shift($quoteItems); + self::assertNull($firstQuoteItem->getParentItemId()); + self::assertEquals($customPrice, (int)$firstQuoteItem->getCustomPrice()); + foreach ($quoteItems as $quoteItem) { + self::assertEquals($firstQuoteItem->getId(), $quoteItem->getParentItemId()); + self::assertEquals(0, (int)$quoteItem->getCustomPrice()); + } + + $shippingMethod = 'freeshipping_freeshipping'; + /** @var Rate $rate */ + $rate = $this->objectManager->create(Rate::class); + $rate->setCode($shippingMethod); + $this->model->getQuote()->getShippingAddress()->addShippingRate($rate); + $this->model->setPaymentData(['method' => 'checkmo']); + $this->model->setIsValidate(true)->importPostData(['shipping_method' => $shippingMethod]); + $newOrder = $this->model->createOrder(); + + /** @var OrderItem[] $orderItems */ + $orderItems = $newOrder->getAllItems(); + $firstOrderItem = array_shift($orderItems); + self::assertNull($firstOrderItem->getParentItemId()); + self::assertEquals($customPrice, (int)$firstOrderItem->getPrice()); + foreach ($orderItems as $orderItem) { + self::assertEquals($firstOrderItem->getId(), $orderItem->getParentItemId()); + self::assertEquals(0, (int)$orderItem->getPrice()); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/order_item_with_configurable_and_options.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/order_item_with_configurable_and_options.php index 47d86b34fc05e..d0956e460f709 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/order_item_with_configurable_and_options.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/order_item_with_configurable_and_options.php @@ -3,6 +3,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\TestFramework\Workaround\Override\Fixture\Resolver; Resolver::getInstance()->requireDataFixture('Magento/ConfigurableProduct/_files/product_configurable.php'); @@ -20,9 +23,11 @@ $payment = $objectManager->create(\Magento\Sales\Model\Order\Payment::class); $payment->setMethod('checkmo'); -/** @var $product \Magento\Catalog\Model\Product */ -$product = $objectManager->create(\Magento\Catalog\Model\Product::class); -$product->load(1); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$product = $productRepository->get('configurable'); +/** @var ProductInterface $firstChildProduct */ +$firstChildProduct = current($product->getTypeInstance()->getUsedProducts($product)); /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ $eavConfig = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Eav\Model\Config::class); @@ -38,6 +43,7 @@ 'super_attribute' => [ $attribute->getId() => $option->getId(), ], + 'custom_price' => 300, ]; /** @var \Magento\Sales\Model\Order $order */ $order = $objectManager->create(\Magento\Sales\Model\Order::class); @@ -54,7 +60,11 @@ $orderItem->setPrice($product->getPrice()); $orderItem->setRowTotal($product->getPrice()); $orderItem->setProductType($product->getTypeId()); -$orderItem->setProductOptions(['info_buyRequest' => $requestInfo]); +$orderItem->setProductOptions([ + 'info_buyRequest' => $requestInfo, + 'simple_sku' => $firstChildProduct->getSku(), + 'simple_name' => $firstChildProduct->getName(), +]); /** @var \Magento\Sales\Model\Order $order */ $order = $objectManager->create(\Magento\Sales\Model\Order::class); From 667e1dce09b0c9e79232a0aed7bc4cb6856882c7 Mon Sep 17 00:00:00 2001 From: engcom-Echo Date: Thu, 12 Nov 2020 14:00:19 +0200 Subject: [PATCH 09/14] MC-38105: Unable to set native session handler that is different from the one define in php.ini --- .../Magento/Framework/Session/SessionManagerTest.php | 2 +- lib/internal/Magento/Framework/Session/SessionManager.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php index 21321b49f2610..310e2c9d7b6ae 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php @@ -326,7 +326,7 @@ public function testConstructor(string $saveMethod): void $this->assertArrayHasKey('session.use_only_cookies', self::$isIniSetInvoked); $this->assertEquals('1', self::$isIniSetInvoked['session.use_only_cookies']); foreach ($sessionConfig->getOptions() as $option => $value) { - if ($option == 'session.save_handler' && $value == 'user') { + if ($option === 'session.save_handler' && !$value === 'memcached') { $this->assertArrayNotHasKey('session.save_handler', self::$isIniSetInvoked); } else { $this->assertArrayHasKey($option, self::$isIniSetInvoked); diff --git a/lib/internal/Magento/Framework/Session/SessionManager.php b/lib/internal/Magento/Framework/Session/SessionManager.php index 039caf202e60e..73ece8277f327 100644 --- a/lib/internal/Magento/Framework/Session/SessionManager.php +++ b/lib/internal/Magento/Framework/Session/SessionManager.php @@ -619,9 +619,9 @@ private function initIniOptions() } foreach ($this->sessionConfig->getOptions() as $option => $value) { - // It is now explicitly forbidden to set the module name to "user". - // Formerly, this has been silently ignored. - if ($option === 'session.save_handler' && $value === 'user') { + // Since PHP 7.2 it is explicitly forbidden to set the module name to "user". + // Need to skip all handlers except memcached. Redis and Db have implements SessionHandlerInterface. + if ($option === 'session.save_handler' && !$value === 'memcached') { continue; } else { $result = ini_set($option, $value); From 2c8b332a4c61de9ad48e0018bfff46244d67c9cd Mon Sep 17 00:00:00 2001 From: engcom-Kilo Date: Wed, 11 Nov 2020 13:23:40 +0200 Subject: [PATCH 10/14] MC-37364: Unit Test and JSUnit Test fails to start on Magento composer 2.4.0 --- .../Test/Unit/Model/Export/ProductTest.php | 3 +- .../ShippingInformationManagementTest.php | 25 ++++++-- .../Checkout/Plugin/GuestValidationTest.php | 21 ++++++- .../Model/Checkout/Plugin/ValidationTest.php | 21 ++++++- .../Test/Unit/Model/Renderer/RegionTest.php | 3 +- .../Unit/Model/Link/UpdateHandlerTest.php | 20 ++++++- .../Quote/Item/CartItemProcessorTest.php | 29 ++++++--- .../Unit/Model/Sample/UpdateHandlerTest.php | 20 ++++++- .../IsAllowedGuestCheckoutObserverTest.php | 6 +- .../Test/Unit/Model/Plugin/OrderGetTest.php | 42 +++++++++++-- .../Test/Unit/Model/Plugin/OrderSaveTest.php | 42 +++++++++++-- .../Unit/Model/DisableMultishippingTest.php | 26 ++++++-- .../Test/Unit/Model/QuoteManagerTest.php | 27 +++++++-- .../Media/ExternalVideoEntryConverterTest.php | 34 ++++++++--- .../Model/ShippingAddressAssignmentTest.php | 21 ++++++- .../Test/Unit/Model/OrderRepositoryTest.php | 59 ++++++++++--------- dev/tests/integration/phpunit.xml.dist | 6 +- .../testsuite/Magento/IntegrationTest.php | 7 ++- dev/tests/unit/phpunit.xml.dist | 1 + 19 files changed, 320 insertions(+), 93 deletions(-) diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Export/ProductTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Export/ProductTest.php index 1ad82497119ba..a71d995f78a8c 100644 --- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Export/ProductTest.php +++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Export/ProductTest.php @@ -172,7 +172,8 @@ protected function setUp(): void $this->productFactory = $this->getMockBuilder( \Magento\Catalog\Model\ResourceModel\ProductFactory::class - )->addMethods(['getTypeId']) + )->disableOriginalConstructor() + ->addMethods(['getTypeId']) ->onlyMethods(['create']) ->getMock(); diff --git a/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php b/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php index 8618626642421..8bb017f4b212c 100644 --- a/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php @@ -148,7 +148,7 @@ protected function setUp(): void 'importCustomerAddressData', 'save', 'getShippingRateByCode', - 'getShippingMethod' + 'getShippingMethod', ] ) ->disableOriginalConstructor() @@ -167,7 +167,7 @@ protected function setUp(): void 'collectTotals', 'getExtensionAttributes', 'setExtensionAttributes', - 'setBillingAddress' + 'setBillingAddress', ] ) ->disableOriginalConstructor() @@ -238,9 +238,7 @@ private function setShippingAssignmentsMocks($shippingMethod): void ->willReturn(null); $this->shippingAddressMock->expects($this->once()) ->method('setLimitCarrier'); - $this->cartExtensionMock = $this->getMockBuilder(CartExtension::class) - ->addMethods(['getShippingAssignments', 'setShippingAssignments']) - ->getMock(); + $this->cartExtensionMock = $this->getCartExtensionMock(); $this->cartExtensionFactoryMock->expects($this->once()) ->method('create') ->willReturn($this->cartExtensionMock); @@ -622,4 +620,21 @@ public function testSaveAddressInformation(): void $this->model->saveAddressInformation($cartId, $addressInformationMock) ); } + + /** + * Build cart extension mock. + * + * @return MockObject + */ + private function getCartExtensionMock(): MockObject + { + $mockBuilder = $this->getMockBuilder(CartExtension::class); + try { + $mockBuilder->addMethods(['getShippingAssignments', 'setShippingAssignments']); + } catch (\RuntimeException $e) { + // CartExtension already generated. + } + + return $mockBuilder->getMock(); + } } diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php index 01e4480956180..845d71f6e2f17 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php @@ -78,9 +78,7 @@ protected function setUp(): void $this->subjectMock = $this->getMockForAbstractClass(GuestPaymentInformationManagementInterface::class); $this->paymentMock = $this->getMockForAbstractClass(PaymentInterface::class); $this->addressMock = $this->getMockForAbstractClass(AddressInterface::class); - $this->extensionAttributesMock = $this->getMockBuilder(PaymentExtension::class) - ->addMethods(['getAgreementIds']) - ->getMock(); + $this->extensionAttributesMock = $this->getPaymentExtension(); $this->scopeConfigMock = $this->getMockForAbstractClass(ScopeConfigInterface::class); $this->checkoutAgreementsListMock = $this->createMock( CheckoutAgreementsListInterface::class @@ -165,4 +163,21 @@ public function testBeforeSavePaymentInformationAndPlaceOrderIfAgreementsNotVali "The order wasn't placed. First, agree to the terms and conditions, then try placing your order again." ); } + + /** + * Build payment extension mock. + * + * @return MockObject + */ + private function getPaymentExtension(): MockObject + { + $mockBuilder = $this->getMockBuilder(PaymentExtension::class); + try { + $mockBuilder->addMethods(['getAgreementIds']); + } catch (\RuntimeException $e) { + // Payment extension already generated. + } + + return $mockBuilder->getMock(); + } } diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php index 7dea366506d66..ebe4c2c1c7b05 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php @@ -96,9 +96,7 @@ protected function setUp(): void ->disableOriginalConstructor() ->getMock(); $this->quoteRepositoryMock = $this->getMockForAbstractClass(CartRepositoryInterface::class); - $this->extensionAttributesMock = $this->getMockBuilder(PaymentExtension::class) - ->addMethods(['getAgreementIds']) - ->getMock(); + $this->extensionAttributesMock = $this->getPaymentExtension(); $this->scopeConfigMock = $this->getMockForAbstractClass(ScopeConfigInterface::class); $this->checkoutAgreementsListMock = $this->createMock( CheckoutAgreementsListInterface::class @@ -232,4 +230,21 @@ public function testBeforeSavePaymentInformation() ->willReturn($this->extensionAttributesMock); $this->model->beforeSavePaymentInformation($this->subjectMock, $cartId, $this->paymentMock, $this->addressMock); } + + /** + * Build payment extension mock. + * + * @return MockObject + */ + private function getPaymentExtension(): MockObject + { + $mockBuilder = $this->getMockBuilder(PaymentExtension::class); + try { + $mockBuilder->addMethods(['getAgreementIds']); + } catch (\RuntimeException $e) { + // Payment extension already generated. + } + + return $mockBuilder->getMock(); + } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Renderer/RegionTest.php b/app/code/Magento/Customer/Test/Unit/Model/Renderer/RegionTest.php index ae48926f12612..37e89c63c8957 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Renderer/RegionTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Renderer/RegionTest.php @@ -66,7 +66,8 @@ function (array $attributes) use ($elementMock): string { } ); $countryMock = $this->getMockBuilder(AbstractElement::class) - ->addMethods(['getValue', 'serialize']) + ->onlyMethods(['serialize']) + ->addMethods(['getValue']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $countryMock->method('serialize')->willReturnCallback( diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Link/UpdateHandlerTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Link/UpdateHandlerTest.php index 22cf4b9abf7ca..af4d785955600 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Model/Link/UpdateHandlerTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Model/Link/UpdateHandlerTest.php @@ -56,7 +56,7 @@ protected function setUp(): void ->getMockForAbstractClass(); $this->linkMock = $this->getMockBuilder(LinkInterface::class) ->getMock(); - $this->productExtensionMock = $this->createMock(ProductExtensionInterface::class); + $this->productExtensionMock = $this->getProductExtensionMock(); $this->productExtensionMock->expects($this->once()) ->method('getDownloadableProductLinks') ->willReturn([$this->linkMock]); @@ -145,4 +145,22 @@ public function testExecuteNonDownloadable(): void $this->assertEquals($this->entityMock, $this->model->execute($this->entityMock)); } + + /** + * Build product extension mock. + * + * @return MockObject + */ + private function getProductExtensionMock(): MockObject + { + $mockBuilder = $this->getMockBuilder(ProductExtensionInterface::class) + ->disableOriginalConstructor(); + try { + $mockBuilder->addMethods(['getDownloadableProductLinks']); + } catch (\RuntimeException $e) { + // ProductExtension already generated. + } + + return $mockBuilder->getMockForAbstractClass(); + } } diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php index c177b117f19d0..46ded7b3c456b 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php @@ -170,14 +170,12 @@ public function testProcessProductOptions() $this->optionFactoryMock->expects($this->once())->method('create')->willReturn($productOptionMock); $productOptionMock->expects($this->once())->method('getExtensionAttributes')->willReturn(null); - $extAttributeMock = $this->getMockBuilder(ProductOptionExtension::class) - ->addMethods(['setDownloadableOption']) - ->getMock(); + $extAttributeMock = $this->getProductOptionExtensionMock(); $this->objectHelperMock->expects($this->once())->method('populateWithArray')->with( $downloadableOptionMock, [ - 'downloadable_links' => $downloadableLinks + 'downloadable_links' => $downloadableLinks, ], DownloadableOptionInterface::class ); @@ -206,9 +204,7 @@ public function testProcessProductOptionsWhenItemDoesNotHaveDownloadableLinks() ->method('getOptionByCode') ->with('downloadable_link_ids'); - $extAttributeMock = $this->getMockBuilder(ProductOptionExtension::class) - ->addMethods(['setDownloadableOption']) - ->getMock(); + $extAttributeMock = $this->getProductOptionExtensionMock(); $productOptionMock = $this->getMockForAbstractClass(ProductOptionInterface::class); $productOptionMock->expects($this->any()) ->method('getExtensionAttributes') @@ -228,7 +224,7 @@ public function testProcessProductOptionsWhenItemDoesNotHaveDownloadableLinks() $this->objectHelperMock->expects($this->once())->method('populateWithArray')->with( $downloadableOptionMock, [ - 'downloadable_links' => $downloadableLinks + 'downloadable_links' => $downloadableLinks, ], DownloadableOptionInterface::class ); @@ -243,4 +239,21 @@ public function testProcessProductOptionsWhenItemDoesNotHaveDownloadableLinks() $this->assertEquals($cartItemMock, $this->model->processOptions($cartItemMock)); } + + /** + * Build product option extension mock. + * + * @return MockObject + */ + private function getProductOptionExtensionMock(): MockObject + { + $mockBuilder = $this->getMockBuilder(ProductOptionExtension::class); + try { + $mockBuilder->addMethods(['setDownloadableOption']); + } catch (\RuntimeException $e) { + // ProductOptionExtension already generated. + } + + return $mockBuilder->getMock(); + } } diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Sample/UpdateHandlerTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Sample/UpdateHandlerTest.php index 0f8fe92e467ce..d826cde3cd78a 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Model/Sample/UpdateHandlerTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Model/Sample/UpdateHandlerTest.php @@ -56,7 +56,7 @@ protected function setUp(): void ->getMockForAbstractClass(); $this->sampleMock = $this->getMockBuilder(SampleInterface::class) ->getMock(); - $this->productExtensionMock = $this->createMock(ProductExtensionInterface::class); + $this->productExtensionMock = $this->getProductExtensionMock(); $this->productExtensionMock//->expects($this->once()) ->method('getDownloadableProductSamples') ->willReturn([$this->sampleMock]); @@ -145,4 +145,22 @@ public function testExecuteNonDownloadable(): void $this->assertEquals($this->entityMock, $this->model->execute($this->entityMock)); } + + /** + * Build product extension mock. + * + * @return MockObject + */ + private function getProductExtensionMock(): MockObject + { + $mockBuilder = $this->getMockBuilder(ProductExtensionInterface::class) + ->disableOriginalConstructor(); + try { + $mockBuilder->addMethods(['getDownloadableProductSamples']); + } catch (\RuntimeException $e) { + // Product extension already generated. + } + + return $mockBuilder->getMockForAbstractClass(); + } } diff --git a/app/code/Magento/Downloadable/Test/Unit/Observer/IsAllowedGuestCheckoutObserverTest.php b/app/code/Magento/Downloadable/Test/Unit/Observer/IsAllowedGuestCheckoutObserverTest.php index 6040b301a60a8..ea4a2769a117b 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Observer/IsAllowedGuestCheckoutObserverTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Observer/IsAllowedGuestCheckoutObserverTest.php @@ -91,13 +91,13 @@ protected function setUp(): void ->getMock(); $this->storeMock = $this->getMockBuilder(DataObject::class) + ->addMethods(['getId']) ->disableOriginalConstructor() ->getMock(); $this->storeManagerMock = $this->getMockForAbstractClass(StoreManagerInterface::class); - $this->storeManagerMock - ->method('getStore') - ->with(self::STUB_STORE_ID) + $this->storeManagerMock->method('getStore') + ->with($this->storeMock) ->willReturn($this->storeMock); $this->isAllowedGuestCheckoutObserver = (new ObjectManagerHelper($this)) diff --git a/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderGetTest.php b/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderGetTest.php index 15c0e1b408ded..d9389f43843a3 100644 --- a/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderGetTest.php +++ b/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderGetTest.php @@ -106,18 +106,14 @@ protected function setUp(): void $this->orderMock = $this->createMock( OrderInterface::class ); - $this->orderExtensionMock = $this->getMockBuilder(OrderExtension::class) - ->addMethods(['getGiftMessage', 'setGiftMessage']) - ->getMock(); + $this->orderExtensionMock = $this->getOrderExtensionMock(); $this->giftMessageMock = $this->createMock( MessageInterface::class ); $this->orderItemMock = $this->createMock( OrderItemInterface::class ); - $this->orderItemExtensionMock = $this->getMockBuilder(OrderItemExtension::class) - ->addMethods(['setGiftMessage', 'getGiftMessage']) - ->getMock(); + $this->orderItemExtensionMock = $this->getOrderItemExtensionMock(); $this->orderRepositoryMock = $this->createMock( \Magento\Sales\Api\OrderRepositoryInterface::class ); @@ -272,4 +268,38 @@ public function testAfterGetList() $this->collectionMock->expects($this->once())->method('getItems')->willReturn([$this->orderMock]); $this->plugin->afterGetList($this->orderRepositoryMock, $this->collectionMock); } + + /** + * Build order extension mock. + * + * @return MockObject + */ + private function getOrderExtensionMock(): MockObject + { + $mockObject = $this->getMockBuilder(OrderExtension::class); + try { + $mockObject->addMethods(['getGiftMessage', 'setGiftMessage']); + } catch (\RuntimeException $e) { + // Order extension already generated. + } + + return $mockObject->getMock(); + } + + /** + * Build order item extension mock. + * + * @return MockObject + */ + private function getOrderItemExtensionMock(): MockObject + { + $mockObject = $this->getMockBuilder(OrderItemExtension::class); + try { + $mockObject->addMethods(['getGiftMessage', 'setGiftMessage']); + } catch (\RuntimeException $e) { + // Order extension already generated. + } + + return $mockObject->getMock(); + } } diff --git a/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderSaveTest.php b/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderSaveTest.php index f6eaa02d9eaab..11491754e3bcb 100644 --- a/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderSaveTest.php +++ b/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderSaveTest.php @@ -76,18 +76,14 @@ protected function setUp(): void $this->orderMock = $this->createMock( OrderInterface::class ); - $this->orderExtensionMock = $this->getMockBuilder(OrderExtension::class) - ->addMethods(['getGiftMessage', 'setGiftMessage']) - ->getMock(); + $this->orderExtensionMock = $this->getOrderExtensionMock(); $this->giftMessageMock = $this->createMock( MessageInterface::class ); $this->orderItemMock = $this->createMock( OrderItemInterface::class ); - $this->orderItemExtensionMock = $this->getMockBuilder(OrderItemExtension::class) - ->addMethods(['setGiftMessage', 'getGiftMessage']) - ->getMock(); + $this->orderItemExtensionMock = $this->getOrderItemExtensionMock(); $this->orderRepositoryMock = $this->createMock( \Magento\Sales\Api\OrderRepositoryInterface::class ); @@ -192,4 +188,38 @@ public function testAfterSaveIfItemGiftMessagesNotExist() ->willThrowException(new \Exception('Test message')); $this->plugin->afterSave($this->orderRepositoryMock, $this->orderMock); } + + /** + * Build order extension mock. + * + * @return MockObject + */ + private function getOrderExtensionMock(): MockObject + { + $mockBuilder = $this->getMockBuilder(OrderExtension::class); + try { + $mockBuilder->addMethods(['getGiftMessage', 'setGiftMessage']); + } catch (\RuntimeException $e) { + // OrderExtension already generated. + } + + return $mockBuilder->getMock(); + } + + /** + * Build order item extension mock. + * + * @return MockObject + */ + private function getOrderItemExtensionMock(): MockObject + { + $mockBuilder = $this->getMockBuilder(OrderItemExtension::class); + try { + $mockBuilder->addMethods(['getGiftMessage', 'setGiftMessage']); + } catch (\RuntimeException $e) { + // OrderItemExtension already generated. + } + + return $mockBuilder->getMock(); + } } diff --git a/app/code/Magento/Multishipping/Test/Unit/Model/DisableMultishippingTest.php b/app/code/Magento/Multishipping/Test/Unit/Model/DisableMultishippingTest.php index 9882f8d1441aa..075fc4ac347b0 100644 --- a/app/code/Magento/Multishipping/Test/Unit/Model/DisableMultishippingTest.php +++ b/app/code/Magento/Multishipping/Test/Unit/Model/DisableMultishippingTest.php @@ -59,11 +59,7 @@ public function testExecuteWithMultishippingModeEnabled(bool $hasShippingAssignm ->method('setIsMultiShipping') ->with(0); - /** @var CartExtensionInterface|MockObject $extensionAttributesMock */ - $extensionAttributesMock = $this->getMockBuilder(CartExtensionInterface::class) - ->addMethods(['getShippingAssignments', 'setShippingAssignments']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); + $extensionAttributesMock = $this->getCartExtensionMock(); $extensionAttributesMock->expects($this->once()) ->method('getShippingAssignments') @@ -90,7 +86,7 @@ public function executeWithMultishippingModeEnabledDataProvider(): array { return [ 'check_with_shipping_assignments' => [true], - 'check_without_shipping_assignments' => [false] + 'check_without_shipping_assignments' => [false], ]; } @@ -113,4 +109,22 @@ public function testExecuteWithMultishippingModeDisabled(): void $this->assertFalse($this->disableMultishippingModel->execute($this->quoteMock)); } + + /** + * Build cart extension mock. + * + * @return MockObject + */ + private function getCartExtensionMock(): MockObject + { + $mockBuilder = $this->getMockBuilder(CartExtensionInterface::class) + ->disableOriginalConstructor(); + try { + $mockBuilder->addMethods(['getShippingAssignments', 'setShippingAssignments']); + } catch (\RuntimeException $e) { + // CartExtension already generated. + } + + return $mockBuilder->getMockForAbstractClass(); + } } diff --git a/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php b/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php index 03d6ab02beb3c..d6d80ab7de229 100644 --- a/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php +++ b/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php @@ -23,6 +23,7 @@ use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\Quote\ShippingAssignment\ShippingAssignmentProcessor; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; /** @@ -94,7 +95,7 @@ protected function setUp(): void 'setCustomerData', 'clearQuote', 'clearStorage', - 'getQuote' + 'getQuote', ]) ->onlyMethods(['removePersistentCookie']) ->disableOriginalConstructor() @@ -115,7 +116,7 @@ protected function setUp(): void 'setCustomerLastname', 'setCustomerGroupId', 'setIsPersistent', - 'getCustomerId' + 'getCustomerId', ]) ->onlyMethods([ 'getId', @@ -132,7 +133,7 @@ protected function setUp(): void 'getExtensionAttributes', 'setExtensionAttributes', '__wakeup', - 'setCustomer' + 'setCustomer', ]) ->disableOriginalConstructor() ->getMock(); @@ -240,8 +241,7 @@ public function testSetGuest() ->method('removePersistentCookie')->willReturn($this->sessionMock); $this->quoteMock->expects($this->once())->method('isVirtual')->willReturn(false); $this->quoteMock->expects($this->once())->method('getItemsQty')->willReturn(1); - $extensionAttributes = $this->getMockBuilder(CartExtensionInterface::class) - ->getMockForAbstractClass(); + $extensionAttributes = $this->getExtensionAttributesMock(); $shippingAssignment = $this->createMock(ShippingAssignmentInterface::class); $extensionAttributes->expects($this->once()) ->method('setShippingAssignments') @@ -381,4 +381,21 @@ public function testConvertCustomerCartToGuestWithEmptyQuoteId() $this->quoteMock->expects($this->once())->method('getId')->willReturn(1); $this->model->convertCustomerCartToGuest(); } + + /** + * Build CartExtensionInterface mock. + * + * @return MockObject + */ + private function getExtensionAttributesMock(): MockObject + { + $extensionMockBuilder = $this->getMockBuilder(CartExtensionInterface::class); + try { + $extensionMockBuilder->addMethods(['setShippingAssignments']); + } catch (\RuntimeException $e) { + // do nothing as CartExtensionInterface already generated and has 'setShippingAssignments' method. + } + + return $extensionMockBuilder->getMockForAbstractClass(); + } } diff --git a/app/code/Magento/ProductVideo/Test/Unit/Model/Product/Attribute/Media/ExternalVideoEntryConverterTest.php b/app/code/Magento/ProductVideo/Test/Unit/Model/Product/Attribute/Media/ExternalVideoEntryConverterTest.php index a921bff76c8d6..fd96ca7fb7ebf 100644 --- a/app/code/Magento/ProductVideo/Test/Unit/Model/Product/Attribute/Media/ExternalVideoEntryConverterTest.php +++ b/app/code/Magento/ProductVideo/Test/Unit/Model/Product/Attribute/Media/ExternalVideoEntryConverterTest.php @@ -81,7 +81,7 @@ protected function setUp(): void 'getContent', 'setContent', 'getExtensionAttributes', - 'setExtensionAttributes' + 'setExtensionAttributes', ] ); @@ -104,11 +104,7 @@ protected function setUp(): void ['create'] ); - $this->mediaGalleryEntryExtensionMock = $this->getMockBuilder(ProductAttributeMediaGalleryEntryExtension::class) - ->addMethods(['getVideoProvider']) - ->onlyMethods(['setVideoContent', 'getVideoContent']) - ->disableOriginalConstructor() - ->getMock(); + $this->mediaGalleryEntryExtensionMock = $this->getProductAttributeMediaGalleryEntryExtensionMock(); $this->mediaGalleryEntryExtensionMock->expects($this->any())->method('setVideoContent')->willReturn(null); $this->mediaGalleryEntryExtensionFactoryMock->expects($this->any())->method('create')->willReturn( @@ -123,7 +119,7 @@ protected function setUp(): void 'mediaGalleryEntryFactory' => $this->mediaGalleryEntryFactoryMock, 'dataObjectHelper' => $this->dataObjectHelperMock, 'videoEntryFactory' => $this->videoEntryFactoryMock, - 'mediaGalleryEntryExtensionFactory' => $this->mediaGalleryEntryExtensionFactoryMock + 'mediaGalleryEntryExtensionFactory' => $this->mediaGalleryEntryExtensionFactoryMock, ] ); } @@ -218,4 +214,28 @@ public function testConvertFrom() $result = $this->modelObject->convertFrom($this->mediaGalleryEntryMock); $this->assertEquals($expectedResult, $result); } + + /** + * Build ProductAttributeMediaGalleryEntryExtension mock. + * + * @return MockObject + */ + private function getProductAttributeMediaGalleryEntryExtensionMock(): MockObject + { + $mockBuilder = $this->getMockBuilder(ProductAttributeMediaGalleryEntryExtension::class) + ->disableOriginalConstructor(); + try { + $mockBuilder->addMethods( + [ + 'getVideoProvider', + 'setVideoContent', + 'getVideoContent', + ] + ); + } catch (\Exception $e) { + // ProductAttributeMediaGalleryEntryExtension already generated and has all necessary methods. + } + + return $mockBuilder->getMock(); + } } diff --git a/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressAssignmentTest.php b/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressAssignmentTest.php index 00cb1d48e8889..75f3af2643722 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressAssignmentTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressAssignmentTest.php @@ -66,9 +66,7 @@ protected function setUp(): void ); $this->quoteMock = $this->createMock(Quote::class); $this->addressMock = $this->createMock(Address::class); - $this->extensionAttributeMock = $this->getMockBuilder(CartExtension::class) - ->addMethods(['setShippingAssignments']) - ->getMock(); + $this->extensionAttributeMock = $this->getCartExtensionMock(); $this->shippingAssignmentMock = $this->getMockForAbstractClass(ShippingAssignmentInterface::class); //shipping assignment processing @@ -113,4 +111,21 @@ public function testSetAddressUseForShippingFalse() $this->quoteMock->expects($this->once())->method('setShippingAddress')->with($addressMock); $this->model->setAddress($this->quoteMock, $this->addressMock, false); } + + /** + * Build cart extension mock. + * + * @return MockObject + */ + private function getCartExtensionMock(): MockObject + { + $mockBuilder = $this->getMockBuilder(CartExtension::class); + try { + $mockBuilder->addMethods(['setShippingAssignments']); + } catch (\RuntimeException $e) { + // CartExtension already generated. + } + + return $mockBuilder->getMock(); + } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderRepositoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderRepositoryTest.php index 2e51bd8d75b89..d242268649a5e 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderRepositoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderRepositoryTest.php @@ -13,8 +13,8 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Payment\Api\Data\PaymentAdditionalInfoInterface; use Magento\Payment\Api\Data\PaymentAdditionalInfoInterfaceFactory; -use Magento\Sales\Api\Data\OrderExtension; use Magento\Sales\Api\Data\OrderExtensionFactory; +use Magento\Sales\Api\Data\OrderExtensionInterface; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\Data\OrderPaymentInterface; use Magento\Sales\Api\Data\OrderSearchResultInterfaceFactory as SearchResultFactory; @@ -111,7 +111,7 @@ protected function setUp(): void 'collectionProcessor' => $this->collectionProcessor, 'orderExtensionFactory' => $this->orderExtensionFactoryMock, 'orderTaxManagement' => $this->orderTaxManagementMock, - 'paymentAdditionalInfoFactory' => $this->paymentAdditionalInfoFactory + 'paymentAdditionalInfoFactory' => $this->paymentAdditionalInfoFactory, ] ); } @@ -138,18 +138,7 @@ public function testGetList() ->disableOriginalConstructor() ->setMethods(['setKey', 'setValue'])->getMockForAbstractClass(); - $extensionAttributes = $this->getMockBuilder(OrderExtension::class) - ->addMethods( - [ - 'getShippingAssignments', - 'setShippingAssignments', - 'setConvertingFromQuote', - 'setAppliedTaxes', - 'setItemAppliedTaxes', - 'setPaymentAdditionalInfo' - ] - ) - ->getMock(); + $extensionAttributes = $this->getOrderExtensionMock(); $shippingAssignmentBuilder = $this->createMock( ShippingAssignmentBuilder::class ); @@ -188,9 +177,7 @@ public function testSave() ->disableOriginalConstructor() ->getMock(); $orderEntity = $this->createMock(Order::class); - $extensionAttributes = $this->getMockBuilder(OrderExtension::class) - ->addMethods(['getShippingAssignments']) - ->getMock(); + $extensionAttributes = $this->getOrderExtensionMock(); $shippingAssignment = $this->getMockBuilder(ShippingAssignment::class) ->disableOriginalConstructor() ->setMethods(['getShipping']) @@ -230,18 +217,7 @@ public function testGet() $paymentMock = $this->getMockBuilder(OrderPaymentInterface::class) ->disableOriginalConstructor()->getMockForAbstractClass(); $paymentMock->expects($this->once())->method('getAdditionalInformation')->willReturn($paymentInfo); - $orderExtension = $this->getMockBuilder(OrderExtension::class) - ->setMethods( - [ - 'getShippingAssignments', - 'setAppliedTaxes', - 'setConvertingFromQuote', - 'setItemAppliedTaxes', - 'setPaymentAdditionalInfo' - ] - ) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); + $orderExtension = $this->getOrderExtensionMock(); $orderExtension->expects($this->once())->method('getShippingAssignments')->willReturn(true); $orderExtension->expects($this->once())->method('setAppliedTaxes')->with($appliedTaxes); $orderExtension->expects($this->once())->method('setConvertingFromQuote')->with(true); @@ -266,4 +242,29 @@ public function testGet() $this->orderRepository->get($orderId); } + + /** + * Buld order extension mock. + * + * @return MockObject + */ + private function getOrderExtensionMock(): MockObject + { + $mockBuilder = $this->getMockBuilder(OrderExtensionInterface::class)->disableOriginalConstructor(); + try { + $mockBuilder->addMethods( + [ + 'getShippingAssignments', + 'setAppliedTaxes', + 'setConvertingFromQuote', + 'setItemAppliedTaxes', + 'setPaymentAdditionalInfo', + ] + ); + } catch (\RuntimeException $e) { + // Order extension already generated. + } + + return $mockBuilder->getMockForAbstractClass(); + } } diff --git a/dev/tests/integration/phpunit.xml.dist b/dev/tests/integration/phpunit.xml.dist index 92dd1e11f613b..d57e6809da7e9 100644 --- a/dev/tests/integration/phpunit.xml.dist +++ b/dev/tests/integration/phpunit.xml.dist @@ -17,14 +17,14 @@ > - + testsuite/Magento/IntegrationTest.php - + testsuite/Magento/MemoryUsageTest.php - + testsuite ../../../app/code/*/*/Test/Integration testsuite/Magento/MemoryUsageTest.php diff --git a/dev/tests/integration/testsuite/Magento/IntegrationTest.php b/dev/tests/integration/testsuite/Magento/IntegrationTest.php index 4626a10884290..39d383fb86354 100644 --- a/dev/tests/integration/testsuite/Magento/IntegrationTest.php +++ b/dev/tests/integration/testsuite/Magento/IntegrationTest.php @@ -41,7 +41,7 @@ public static function suite($className) $suitesConfig = $configuration->testSuite(); $suite = new TestSuite(); foreach ($suitesConfig as $suiteConfig) { - if ($suiteConfig->name() === 'Magento Integration Tests') { + if ($suiteConfig->name() === 'Magento_Integration_Tests') { continue; } $suites = self::getSuites($suiteConfig); @@ -73,7 +73,10 @@ public static function suite($className) private static function getConfigurationFile(): string { $params = getopt('c:', ['configuration:']); - $longConfig = $params['configuration'] ?? ''; + $defaultConfigFile = file_exists(__DIR__ . '../../phpunit.xml') + ? __DIR__ . '/../../phpunit.xml' + : __DIR__ . '/../../phpunit.xml.dist'; + $longConfig = $params['configuration'] ?? $defaultConfigFile; $shortConfig = $params['c'] ?? ''; return $shortConfig ? $shortConfig : $longConfig; diff --git a/dev/tests/unit/phpunit.xml.dist b/dev/tests/unit/phpunit.xml.dist index 1793b0f698310..709bb7c1ea95b 100644 --- a/dev/tests/unit/phpunit.xml.dist +++ b/dev/tests/unit/phpunit.xml.dist @@ -15,6 +15,7 @@ ../../../app/code/*/*/Test/Unit + ../../../vendor/magento/module-*/Test/Unit ../../../lib/internal/*/*/Test/Unit From caefb4e63f0c726c996118c2707afaf63ed3c665 Mon Sep 17 00:00:00 2001 From: engcom-Echo Date: Thu, 12 Nov 2020 14:21:04 +0200 Subject: [PATCH 11/14] MC-38105: Unable to set native session handler that is different from the one define in php.ini --- .../Magento/Framework/Session/SessionManagerTest.php | 8 ++++---- lib/internal/Magento/Framework/Session/SessionManager.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php index 310e2c9d7b6ae..6a461c3007ca7 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php @@ -326,11 +326,11 @@ public function testConstructor(string $saveMethod): void $this->assertArrayHasKey('session.use_only_cookies', self::$isIniSetInvoked); $this->assertEquals('1', self::$isIniSetInvoked['session.use_only_cookies']); foreach ($sessionConfig->getOptions() as $option => $value) { - if ($option === 'session.save_handler' && !$value === 'memcached') { - $this->assertArrayNotHasKey('session.save_handler', self::$isIniSetInvoked); + if ($option === 'session.save_handler' && $value !== 'memcached') { + $this->assertArrayNotHasKey('session.save_handler', self::$isIniSetInvoked); } else { - $this->assertArrayHasKey($option, self::$isIniSetInvoked); - $this->assertEquals($value, self::$isIniSetInvoked[$option]); + $this->assertArrayHasKey($option, self::$isIniSetInvoked); + $this->assertEquals($value, self::$isIniSetInvoked[$option]); } } $this->assertTrue(self::$isSessionSetSaveHandlerInvoked); diff --git a/lib/internal/Magento/Framework/Session/SessionManager.php b/lib/internal/Magento/Framework/Session/SessionManager.php index 73ece8277f327..90b49a32a7851 100644 --- a/lib/internal/Magento/Framework/Session/SessionManager.php +++ b/lib/internal/Magento/Framework/Session/SessionManager.php @@ -620,8 +620,8 @@ private function initIniOptions() foreach ($this->sessionConfig->getOptions() as $option => $value) { // Since PHP 7.2 it is explicitly forbidden to set the module name to "user". - // Need to skip all handlers except memcached. Redis and Db have implements SessionHandlerInterface. - if ($option === 'session.save_handler' && !$value === 'memcached') { + // https://bugs.php.net/bug.php?id=77384 + if ($option === 'session.save_handler' && $value !== 'memcached') { continue; } else { $result = ini_set($option, $value); From 8285894e91aa5ee57119ee7cdbe8006ed85d2b59 Mon Sep 17 00:00:00 2001 From: Viktor Kopin Date: Fri, 13 Nov 2020 15:15:39 +0200 Subject: [PATCH 12/14] MC-30348: Rest salesShipOrderV1 API w/ Bundles error: "You can't create a shipment without products" --- .../Shipment/BundleShipmentTypeValidator.php | 51 ++++ app/code/Magento/Bundle/etc/di.xml | 7 + app/code/Magento/Bundle/i18n/en_US.csv | 3 + .../Order/Shipment/ShipmentItemsValidator.php | 62 +++++ .../ShipmentItemsValidatorInterface.php | 27 ++ .../Model/Order/Validation/ShipOrder.php | 69 +++++- .../Magento/Sales/Model/ValidatorResult.php | 16 +- app/code/Magento/Sales/etc/di.xml | 1 + .../Sales/Service/V1/ShipOrderTest.php | 136 +++++++++- .../order_with_bundle_shipped_separately.php | 123 ++++++---- .../order_with_bundle_shipped_together.php | 232 ++++++++++++++++++ ..._with_bundle_shipped_together_rollback.php | 11 + 12 files changed, 666 insertions(+), 72 deletions(-) create mode 100644 app/code/Magento/Bundle/Model/Sales/Order/Shipment/BundleShipmentTypeValidator.php create mode 100644 app/code/Magento/Sales/Model/Order/Shipment/ShipmentItemsValidator.php create mode 100644 app/code/Magento/Sales/Model/Order/Shipment/ShipmentItemsValidatorInterface.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_together.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_together_rollback.php diff --git a/app/code/Magento/Bundle/Model/Sales/Order/Shipment/BundleShipmentTypeValidator.php b/app/code/Magento/Bundle/Model/Sales/Order/Shipment/BundleShipmentTypeValidator.php new file mode 100644 index 0000000000000..396f19e739347 --- /dev/null +++ b/app/code/Magento/Bundle/Model/Sales/Order/Shipment/BundleShipmentTypeValidator.php @@ -0,0 +1,51 @@ +isDummy(true)) { + return $result; + } + + $message = 'Cannot create shipment as bundle product "%1" has shipment type "%2". ' . + '%3 should be shipped instead.'; + + if ($item->getHasChildren() && $item->getProductType() === Type::TYPE_BUNDLE) { + $result[] = __( + $message, + $item->getSku(), + __('Separately'), + __('Bundle product options'), + ); + } + + if ($item->getParentItem() && $item->getParentItem()->getProductType() === Type::TYPE_BUNDLE) { + $result[] = __( + $message, + $item->getParentItem()->getSku(), + __('Together'), + __('Bundle product itself'), + ); + } + + return $result; + } +} diff --git a/app/code/Magento/Bundle/etc/di.xml b/app/code/Magento/Bundle/etc/di.xml index 6c1a5ab2e7257..9bfa450175ecc 100644 --- a/app/code/Magento/Bundle/etc/di.xml +++ b/app/code/Magento/Bundle/etc/di.xml @@ -234,4 +234,11 @@ + + + + Magento\Bundle\Model\Sales\Order\Shipment\BundleShipmentTypeValidator + + + diff --git a/app/code/Magento/Bundle/i18n/en_US.csv b/app/code/Magento/Bundle/i18n/en_US.csv index ad9fad974e38f..99ef117fffadb 100644 --- a/app/code/Magento/Bundle/i18n/en_US.csv +++ b/app/code/Magento/Bundle/i18n/en_US.csv @@ -105,3 +105,6 @@ Select...,Select... Status,Status Thumbnail,Thumbnail Type,Type +"Cannot create shipment as bundle product ""%1"" has shipment type ""%2"". %3 should be shipped instead.","Cannot create shipment as bundle product ""%1"" has shipment type ""%2"". %3 should be shipped instead." +"Bundle product itself","Bundle product itself" +"Bundle product options","Bundle product options" diff --git a/app/code/Magento/Sales/Model/Order/Shipment/ShipmentItemsValidator.php b/app/code/Magento/Sales/Model/Order/Shipment/ShipmentItemsValidator.php new file mode 100644 index 0000000000000..2112ef6066bd3 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Shipment/ShipmentItemsValidator.php @@ -0,0 +1,62 @@ +validatorResultFactory = $validatorResult; + $this->validators = $validators; + } + + /** + * @inheritdoc + */ + public function validate(array $items): ValidatorResultInterface + { + $messages = []; + foreach ($this->validators as $validator) { + if (!$validator instanceof ValidatorInterface) { + throw new ConfigurationMismatchException( + __( + 'The "%1" validator is not an instance of the general validator interface.', + get_class($validator) + ) + ); + } + foreach ($items as $item) { + $messages[] = $validator->validate($item); + } + } + + return $this->validatorResultFactory->create(['messages' => array_merge([], ...$messages)]); + } +} diff --git a/app/code/Magento/Sales/Model/Order/Shipment/ShipmentItemsValidatorInterface.php b/app/code/Magento/Sales/Model/Order/Shipment/ShipmentItemsValidatorInterface.php new file mode 100644 index 0000000000000..557feacb2de48 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Shipment/ShipmentItemsValidatorInterface.php @@ -0,0 +1,27 @@ +orderValidator = $orderValidator; $this->shipmentValidator = $shipmentValidator; $this->validatorResultMerger = $validatorResultMerger; + $this->itemsValidator = $itemsValidator + ?? ObjectManager::getInstance()->get(ShipmentItemsValidatorInterface::class); } /** + * Order shipment validate + * * @param OrderInterface $order * @param ShipmentInterface $shipment * @param array $items * @param bool $notify * @param bool $appendComment - * @param \Magento\Sales\Api\Data\ShipmentCommentCreationInterface|null $comment + * @param ShipmentCommentCreationInterface|null $comment * @param array $tracks * @param array $packages - * @param \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface|null $arguments - * @return \Magento\Sales\Model\ValidatorResultInterface + * @param ShipmentCreationArgumentsInterface|null $arguments + * @return ValidatorResultInterface */ public function validate( $order, @@ -68,10 +84,10 @@ public function validate( array $items = [], $notify = false, $appendComment = false, - \Magento\Sales\Api\Data\ShipmentCommentCreationInterface $comment = null, + ShipmentCommentCreationInterface $comment = null, array $tracks = [], array $packages = [], - \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface $arguments = null + ShipmentCreationArgumentsInterface $arguments = null ) { $orderValidationResult = $this->orderValidator->validate( $order, @@ -87,6 +103,39 @@ public function validate( ] ); - return $this->validatorResultMerger->merge($orderValidationResult, $shipmentValidationResult); + $orderItems = $this->getRequestedOrderItems($items, $order); + $itemsValidationResult = $this->itemsValidator->validate($orderItems); + + return $this->validatorResultMerger->merge( + $orderValidationResult, + $shipmentValidationResult, + $itemsValidationResult->getMessages() + ); + } + + /** + * Return requested order items + * + * @param OrderItemInterface[] $items + * @param OrderInterface $order + * @return OrderItemInterface[] + */ + private function getRequestedOrderItems(array $items, OrderInterface $order): array + { + $requestedItemIds = array_reduce( + $items, + function (array $result, ShipmentItemCreationInterface $item): array { + $result[] = $item->getOrderItemId(); + return $result; + }, + [] + ); + + return array_filter( + $order->getAllItems(), + function (OrderItemInterface $orderItem) use ($requestedItemIds): bool { + return in_array($orderItem->getId(), $requestedItemIds); + } + ); } } diff --git a/app/code/Magento/Sales/Model/ValidatorResult.php b/app/code/Magento/Sales/Model/ValidatorResult.php index b326ebb4b8b37..feb93c02d5aae 100644 --- a/app/code/Magento/Sales/Model/ValidatorResult.php +++ b/app/code/Magento/Sales/Model/ValidatorResult.php @@ -6,14 +6,22 @@ namespace Magento\Sales\Model; /** - * Class ValidatorResult + * Validation result messages class */ class ValidatorResult implements ValidatorResultInterface { /** * @var \string[] */ - private $messages = []; + private $messages; + + /** + * @param array $messages + */ + public function __construct(array $messages = []) + { + $this->messages = $messages; + } /** * @inheritdoc @@ -24,7 +32,7 @@ public function addMessage($message) } /** - * @return bool + * @inheritdoc */ public function hasMessages() { @@ -32,7 +40,7 @@ public function hasMessages() } /** - * @return \string[] + * @inheritdoc */ public function getMessages() { diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml index b4dadfa944a5b..55c3988cb4ac5 100644 --- a/app/code/Magento/Sales/etc/di.xml +++ b/app/code/Magento/Sales/etc/di.xml @@ -117,6 +117,7 @@ + diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php index 64fc612120332..173e817c94c4a 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php @@ -3,9 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Sales\Service\V1; use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product\Type; use Magento\Framework\ObjectManagerInterface; use Magento\Sales\Api\Data\OrderItemInterface; use Magento\Sales\Api\ShipmentRepositoryInterface; @@ -105,7 +108,7 @@ public function testShipOrderStatusPreserve() $this->assertEquals($orderStatus, $order->getStatus()); $requestData = [ - 'orderId' => $order->getId() + 'orderId' => $order->getId(), ]; /** @var OrderItemInterface $item */ foreach ($order->getAllItems() as $item) { @@ -145,9 +148,9 @@ public function testShipOrder() [ 'track_number' => 'TEST_TRACK_0001', 'title' => 'Simple shipment track', - 'carrier_code' => 'UPS' - ] - ] + 'carrier_code' => 'UPS', + ], + ], ]; /** @var OrderItemInterface $item */ @@ -205,9 +208,9 @@ public function testShipOrderWithoutTrackingNumberReturnsError() 'tracks' => [ [ 'title' => 'Simple shipment track', - 'carrier_code' => 'UPS' - ] - ] + 'carrier_code' => 'UPS', + ], + ], ]; $this->_webApiCall($this->getServiceInfo($existingOrder), $requestData); @@ -231,9 +234,9 @@ public function testPartialShipOrderWithBundleShippedSeparately() [ 'track_number' => 'TEST_TRACK_0001', 'title' => 'Simple shipment track', - 'carrier_code' => 'UPS' - ] - ] + 'carrier_code' => 'UPS', + ], + ], ]; $shippedItemId = null; @@ -267,8 +270,9 @@ public function testPartialShipOrderWithBundleShippedSeparately() if ($item->getItemId() == $shippedItemId) { $this->assertEquals(1, $item->getQtyShipped()); continue; + } elseif ($item->getParentItem()) { + $this->assertEquals(0, $item->getQtyShipped()); } - $this->assertEquals(0, $item->getQtyShipped()); } } @@ -336,6 +340,116 @@ public function testPartialShipOrderWithTwoBundleShippedSeparatelyContainsSameSi } } + /** + * @magentoApiDataFixture Magento/Bundle/_files/order_with_bundle_shipped_separately.php + */ + public function testValidationShipTogetherWithBundleShippedSeparate() + { + $order = $this->getOrder('100000001'); + + $requestData = [ + 'orderId' => $order->getId(), + 'items' => [], + 'comment' => [ + 'comment' => 'Test Comment', + 'is_visible_on_front' => 1, + ], + 'tracks' => [], + ]; + + foreach ($order->getAllItems() as $item) { + if ($item->getProductType() === Type::TYPE_BUNDLE) { + $requestData['items'][] = [ + 'order_item_id' => $item->getItemId(), + 'qty' => $item->getQtyOrdered(), + ]; + break; + } + } + + try { + $this->_webApiCall($this->getServiceInfo($order), $requestData); + $this->fail('Expected exception was not raised'); + } catch (\Exception $exception) { + $this->assertExceptionMessage( + $exception, + 'Shipment Document Validation Error(s): ' + . 'You can\'t create a shipment without products. ' + . 'Cannot create shipment as bundle product "bundle-product" has shipment type "Separately". ' + . 'Bundle product options should be shipped instead.' + ); + } + + foreach ($order->getAllItems() as $item) { + if ($item->getProductType() === Type::TYPE_SIMPLE) { + $requestData['items'] = [ + [ + 'order_item_id' => $item->getItemId(), + 'qty' => $item->getQtyOrdered(), + ], + ]; + break; + } + } + + $this->_webApiCall($this->getServiceInfo($order), $requestData); + } + + /** + * @magentoApiDataFixture Magento/Bundle/_files/order_with_bundle_shipped_together.php + */ + public function testValidationShipTogetherWithBundleShippedTogether() + { + $order = $this->getOrder('100000001'); + + $requestData = [ + 'orderId' => $order->getId(), + 'items' => [], + 'comment' => [ + 'comment' => 'Test Comment', + 'is_visible_on_front' => 1, + ], + 'tracks' => [], + ]; + + foreach ($order->getAllItems() as $item) { + if ($item->getProductType() === Type::TYPE_SIMPLE) { + $requestData['items'][] = [ + 'order_item_id' => $item->getItemId(), + 'qty' => $item->getQtyOrdered(), + ]; + break; + } + } + + try { + $this->_webApiCall($this->getServiceInfo($order), $requestData); + $this->fail('Expected exception was not raised'); + } catch (\Exception $exception) { + $this->assertExceptionMessage( + $exception, + 'Shipment Document Validation Error(s): ' + . 'You can\'t create a shipment without products. ' + . 'Cannot create shipment as bundle product "bundle-product" has shipment type "Together". ' + . 'Bundle product itself should be shipped instead.' + ); + } + + foreach ($order->getAllItems() as $item) { + if ($item->getProductType() === Type::TYPE_BUNDLE) { + $requestData['items'] = [ + [ + 'order_item_id' => $item->getItemId(), + 'qty' => $item->getQtyOrdered(), + ], + ]; + break; + } + } + + $this->_webApiCall($this->getServiceInfo($order), $requestData); + } + /** * @param Order $order * @return array diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_separately.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_separately.php index b91d479cdf1ef..7d214e8ab45a7 100644 --- a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_separately.php +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_separately.php @@ -3,32 +3,56 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - +declare(strict_types=1); + +use Magento\Bundle\Api\Data\LinkInterface; +use Magento\Bundle\Api\Data\LinkInterfaceFactory; +use Magento\Bundle\Api\Data\OptionInterfaceFactory; +use Magento\Bundle\Model\Option; +use Magento\Bundle\Model\Product\Price; +use Magento\Bundle\Model\Product\Type; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type\AbstractType; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Catalog\Model\ProductFactory; +use Magento\Framework\ObjectManagerInterface; +use Magento\Sales\Api\OrderPaymentRepositoryInterface as PaymentFactory; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Address; +use Magento\Sales\Model\Order\Item; +use Magento\Sales\Model\Order\ItemFactory; +use Magento\Sales\Model\OrderFactory; +use Magento\Sales\Model\OrderRepository; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\Workaround\Override\Fixture\Resolver; Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/products.php'); -/** @var $objectManager \Magento\TestFramework\ObjectManager */ -$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); -/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ -$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); +/** @var ObjectManagerInterface $objectManager */ +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); $sampleProduct = $productRepository->get('simple'); $secondSampleProduct = $productRepository->get('custom-design-simple-product'); +$productFactory = $objectManager->get(ProductFactory::class); -/** @var $product \Magento\Catalog\Model\Product */ -$product = $objectManager->create(\Magento\Catalog\Model\Product::class); -$product->setTypeId('bundle') +/** @var $product Product */ +$product = $productFactory->create(); +$product->setTypeId(Type::TYPE_CODE) ->setId(3) - ->setAttributeSetId(4) + ->setAttributeSetId($product->getDefaultAttributeSetId()) ->setWebsiteIds([1]) ->setName('Bundle Product') ->setSku('bundle-product') - ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) - ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) ->setPriceView(1) - ->setPriceType(1) - ->setShipmentType(1) + ->setPriceType(Price::PRICE_TYPE_FIXED) + ->setShipmentType(AbstractType::SHIPMENT_SEPARATELY) ->setPrice(10.0) ->setBundleOptionsData( [ @@ -46,7 +70,7 @@ 'required' => 1, 'delete' => '', ], - ] + ], ) ->setBundleSelectionsData( [ @@ -65,16 +89,15 @@ 'selection_can_change_qty' => 1, 'delete' => '', ], - ] - ] + ], + ], ); if ($product->getBundleOptionsData()) { $options = []; foreach ($product->getBundleOptionsData() as $key => $optionData) { if (!(bool)$optionData['delete']) { - $option = $objectManager->create(\Magento\Bundle\Api\Data\OptionInterfaceFactory::class) - ->create(['data' => $optionData]); + $option = $objectManager->get(OptionInterfaceFactory::class)->create(['data' => $optionData]); $option->setSku($product->getSku()); $option->setOptionId(null); @@ -83,9 +106,8 @@ if (!empty($bundleLinks[$key])) { foreach ($bundleLinks[$key] as $linkData) { if (!(bool)$linkData['delete']) { - /** @var \Magento\Bundle\Api\Data\LinkInterface$link */ - $link = $objectManager->create(\Magento\Bundle\Api\Data\LinkInterfaceFactory::class) - ->create(['data' => $linkData]); + /** @var LinkInterface $link */ + $link = $objectManager->get(LinkInterfaceFactory::class)->create(['data' => $linkData]); $linkProduct = $productRepository->getById($linkData['product_id']); $link->setSku($linkProduct->getSku()); $link->setQty($linkData['selection_qty']); @@ -104,26 +126,22 @@ $extension->setBundleProductOptions($options); $product->setExtensionAttributes($extension); } -$product->save(); - -$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$productRepository->save($product); $addressData = include __DIR__ . '/../../../Magento/Sales/_files/address_data.php'; -$billingAddress = $objectManager->create(\Magento\Sales\Model\Order\Address::class, ['data' => $addressData]); +$billingAddress = $objectManager->create(Address::class, ['data' => $addressData]); $billingAddress->setAddressType('billing'); $shippingAddress = clone $billingAddress; $shippingAddress->setId(null)->setAddressType('shipping'); -$payment = $objectManager->create(\Magento\Sales\Model\Order\Payment::class); -$payment->setMethod('checkmo'); +$paymentFactory = $objectManager->get(PaymentFactory::class); +$payment = $paymentFactory->create()->setMethod('checkmo'); -/** @var $product \Magento\Catalog\Model\Product */ -$product = $objectManager->create(\Magento\Catalog\Model\Product::class); -$product->load(3); +$product = $productRepository->getById(3); -/** @var $typeInstance \Magento\Bundle\Model\Product\Type */ +/** @var $typeInstance Type */ $typeInstance = $product->getTypeInstance(); $typeInstance->setStoreFilter($product->getStoreId(), $product); $optionCollection = $typeInstance->getOptionsCollection($product); @@ -132,7 +150,7 @@ $bundleOptionsQty = []; $optionsData = []; foreach ($optionCollection as $option) { - /** @var $option \Magento\Bundle\Model\Option */ + /** @var $option Option */ $selectionsCollection = $typeInstance->getSelectionsCollection([$option->getId()], $product); if ($option->isMultiSelection()) { $optionsData[$option->getId()] = array_column($selectionsCollection->toArray(), 'product_id'); @@ -151,41 +169,52 @@ 'qty' => 1, ]; +$orderItemFactory = $objectManager->get(ItemFactory::class); $orderItems = []; -/** @var \Magento\Sales\Model\Order\Item $orderItem */ -$orderItem = $objectManager->create(\Magento\Sales\Model\Order\Item::class); +/** @var Item $orderItem */ +$orderItem = $orderItemFactory->create(); $orderItem->setProductId($product->getId()); $orderItem->setQtyOrdered(1); $orderItem->setBasePrice($product->getPrice()); $orderItem->setPrice($product->getPrice()); $orderItem->setRowTotal($product->getPrice()); $orderItem->setProductType($product->getTypeId()); -$orderItem->setProductOptions(['info_buyRequest' => $requestInfo]); +$orderItem->setSku($product->getSku()); +$orderItem->setProductOptions([ + 'info_buyRequest' => $requestInfo, + 'shipment_type' => AbstractType::SHIPMENT_SEPARATELY +]); $orderItems[] = $orderItem; foreach ($optionsData as $optionId => $productId) { - /** @var $selectedProduct \Magento\Catalog\Model\Product */ - $selectedProduct = $objectManager->create(\Magento\Catalog\Model\Product::class); - $selectedProduct->load($productId); + /** @var $selectedProduct Product */ + $selectedProduct = $productRepository->getById($productId); - /** @var \Magento\Sales\Model\Order\Item $orderItem */ - $orderItem = $objectManager->create(\Magento\Sales\Model\Order\Item::class); + /** @var Item $orderItem */ + $orderItem = $orderItemFactory->create(); $orderItem->setProductId($productId); $orderItem->setQtyOrdered(1); $orderItem->setBasePrice($selectedProduct->getPrice()); $orderItem->setPrice($selectedProduct->getPrice()); $orderItem->setRowTotal($selectedProduct->getPrice()); $orderItem->setProductType($selectedProduct->getTypeId()); - $orderItem->setProductOptions(['info_buyRequest' => $requestInfo]); + $orderItem->setSku($selectedProduct->getSku()); + $orderItem->setProductOptions([ + 'info_buyRequest' => $requestInfo, + 'shipment_type' => AbstractType::SHIPMENT_SEPARATELY + ]); + $orderItem->setParentItem($orderItems[0]); $orderItems[] = $orderItem; } -/** @var \Magento\Sales\Model\Order $order */ -$order = $objectManager->create(\Magento\Sales\Model\Order::class); +$orderFactory = $objectManager->get(OrderFactory::class); +$orderRepository = $objectManager->get(OrderRepository::class); +/** @var Order $order */ +$order = $orderFactory->create(); $order->setIncrementId('100000001'); -$order->setState(\Magento\Sales\Model\Order::STATE_NEW); -$order->setStatus($order->getConfig()->getStateDefaultStatus(\Magento\Sales\Model\Order::STATE_NEW)); +$order->setState(Order::STATE_NEW); +$order->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_NEW)); $order->setCustomerIsGuest(true); $order->setCustomerEmail('customer@null.com'); $order->setCustomerFirstname('firstname'); @@ -199,8 +228,8 @@ $order->addItem($item); } -$order->setStoreId($objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->getStore()->getId()); +$order->setStoreId($objectManager->get(StoreManagerInterface::class)->getStore()->getId()); $order->setSubtotal(100); $order->setBaseSubtotal(100); $order->setBaseGrandTotal(100); -$order->save(); +$orderRepository->save($order); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_together.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_together.php new file mode 100644 index 0000000000000..4cc8c96ae9697 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_together.php @@ -0,0 +1,232 @@ +requireDataFixture('Magento/Catalog/_files/products.php'); + +/** @var ObjectManagerInterface $objectManager */ +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$sampleProduct = $productRepository->get('simple'); +$secondSampleProduct = $productRepository->get('custom-design-simple-product'); +$productFactory = $objectManager->get(ProductFactory::class); + +/** @var $product Product */ +$product = $productFactory->create(); +$product->setTypeId(Type::TYPE_CODE) + ->setId(3) + ->setAttributeSetId($product->getDefaultAttributeSetId()) + ->setWebsiteIds([1]) + ->setName('Bundle Product') + ->setSku('bundle-product') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setPriceView(1) + ->setPriceType(Price::PRICE_TYPE_FIXED) + ->setShipmentType(AbstractType::SHIPMENT_TOGETHER) + ->setPrice(10.0) + ->setBundleOptionsData( + [ + [ + 'title' => 'Bundle Product Items', + 'default_title' => 'Bundle Product Items', + 'type' => 'select', + 'required' => 1, + 'delete' => '', + ], + [ + 'title' => 'Bundle Product Items Option 2', + 'default_title' => 'Bundle Product Items Option 2', + 'type' => 'select', + 'required' => 1, + 'delete' => '', + ], + ], + ) + ->setBundleSelectionsData( + [ + [ + [ + 'product_id' => $sampleProduct->getId(), + 'selection_qty' => 1, + 'selection_can_change_qty' => 1, + 'delete' => '', + ], + ], + [ + [ + 'product_id' => $secondSampleProduct->getId(), + 'selection_qty' => 1, + 'selection_can_change_qty' => 1, + 'delete' => '', + ], + ], + ], + ); + +if ($product->getBundleOptionsData()) { + $options = []; + foreach ($product->getBundleOptionsData() as $key => $optionData) { + if (!(bool)$optionData['delete']) { + $option = $objectManager->get(OptionInterfaceFactory::class)->create(['data' => $optionData]); + $option->setSku($product->getSku()); + $option->setOptionId(null); + + $links = []; + $bundleLinks = $product->getBundleSelectionsData(); + if (!empty($bundleLinks[$key])) { + foreach ($bundleLinks[$key] as $linkData) { + if (!(bool)$linkData['delete']) { + /** @var LinkInterface $link */ + $link = $objectManager->get(LinkInterfaceFactory::class)->create(['data' => $linkData]); + $linkProduct = $productRepository->getById($linkData['product_id']); + $link->setSku($linkProduct->getSku()); + $link->setQty($linkData['selection_qty']); + if (isset($linkData['selection_can_change_qty'])) { + $link->setCanChangeQuantity($linkData['selection_can_change_qty']); + } + $links[] = $link; + } + } + $option->setProductLinks($links); + $options[] = $option; + } + } + } + $extension = $product->getExtensionAttributes(); + $extension->setBundleProductOptions($options); + $product->setExtensionAttributes($extension); +} +$productRepository->save($product); + +$addressData = include __DIR__ . '/../../../Magento/Sales/_files/address_data.php'; + +$billingAddress = $objectManager->create(Address::class, ['data' => $addressData]); +$billingAddress->setAddressType('billing'); + +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null)->setAddressType('shipping'); + +$paymentFactory = $objectManager->get(PaymentFactory::class); +$payment = $paymentFactory->create()->setMethod('checkmo'); + +$product = $productRepository->getById(3); + +/** @var $typeInstance Type */ +$typeInstance = $product->getTypeInstance(); +$typeInstance->setStoreFilter($product->getStoreId(), $product); +$optionCollection = $typeInstance->getOptionsCollection($product); + +$bundleOptions = []; +$bundleOptionsQty = []; +$optionsData = []; +foreach ($optionCollection as $option) { + /** @var $option Option */ + $selectionsCollection = $typeInstance->getSelectionsCollection([$option->getId()], $product); + if ($option->isMultiSelection()) { + $optionsData[$option->getId()] = array_column($selectionsCollection->toArray(), 'product_id'); + $bundleOptions[$option->getId()] = array_column($selectionsCollection->toArray(), 'selection_id'); + } else { + $bundleOptions[$option->getId()] = $selectionsCollection->getFirstItem()->getSelectionId(); + $optionsData[$option->getId()] = $selectionsCollection->getFirstItem()->getProductId(); + } + $bundleOptionsQty[$option->getId()] = 1; +} + +$requestInfo = [ + 'product' => $product->getId(), + 'bundle_option' => $bundleOptions, + 'bundle_option_qty' => $bundleOptionsQty, + 'qty' => 1, +]; + +$orderItemFactory = $objectManager->get(ItemFactory::class); +$orderItems = []; +/** @var Item $orderItem */ +$orderItem = $orderItemFactory->create(); +$orderItem->setProductId($product->getId()); +$orderItem->setQtyOrdered(1); +$orderItem->setBasePrice($product->getPrice()); +$orderItem->setPrice($product->getPrice()); +$orderItem->setRowTotal($product->getPrice()); +$orderItem->setProductType($product->getTypeId()); +$orderItem->setSku($product->getSku()); +$orderItem->setProductOptions([ + 'info_buyRequest' => $requestInfo, + 'bundle_options' => [['value' => [['title' => $sampleProduct->getSku()]]]], +]); + +$orderItems[] = $orderItem; + +foreach ($optionsData as $optionId => $productId) { + /** @var $selectedProduct Product */ + $selectedProduct = $productRepository->getById($productId); + + /** @var Item $orderItem */ + $orderItem = $orderItemFactory->create(); + $orderItem->setProductId($productId); + $orderItem->setQtyOrdered(1); + $orderItem->setBasePrice($selectedProduct->getPrice()); + $orderItem->setPrice($selectedProduct->getPrice()); + $orderItem->setRowTotal($selectedProduct->getPrice()); + $orderItem->setProductType($selectedProduct->getTypeId()); + $orderItem->setSku($selectedProduct->getSku()); + $orderItem->setProductOptions(['info_buyRequest' => $requestInfo]); + $orderItem->setParentItem($orderItems[0]); + $orderItems[] = $orderItem; +} + +$orderFactory = $objectManager->get(OrderFactory::class); +$orderRepository = $objectManager->get(OrderRepository::class); +/** @var Order $order */ +$order = $orderFactory->create(); +$order->setIncrementId('100000001'); +$order->setState(Order::STATE_NEW); +$order->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_NEW)); +$order->setCustomerIsGuest(true); +$order->setCustomerEmail('customer@null.com'); +$order->setCustomerFirstname('firstname'); +$order->setCustomerLastname('lastname'); +$order->setBillingAddress($billingAddress); +$order->setShippingAddress($shippingAddress); +$order->setAddresses([$billingAddress, $shippingAddress]); +$order->setPayment($payment); + +foreach ($orderItems as $item) { + $order->addItem($item); +} + +$order->setStoreId($objectManager->get(StoreManagerInterface::class)->getStore()->getId()); +$order->setSubtotal(100); +$order->setBaseSubtotal(100); +$order->setBaseGrandTotal(100); +$orderRepository->save($order); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_together_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_together_rollback.php new file mode 100644 index 0000000000000..4b113164d4ef2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_together_rollback.php @@ -0,0 +1,11 @@ +requireDataFixture('Magento/Bundle/_files/product_rollback.php'); +Resolver::getInstance()->requireDataFixture('Magento/Sales/_files/default_rollback.php'); From 1bf65baa12383fd83f1cb3ad33569271bcbd2692 Mon Sep 17 00:00:00 2001 From: Viktor Kopin Date: Mon, 16 Nov 2020 15:54:16 +0200 Subject: [PATCH 13/14] MC-38788: setup:upgrade not possible in after installing Sample Data Magento --- .../Model/Adapter/Elasticsearch.php | 92 ++++++--- .../Model/Adapter/ElasticsearchTest.php | 194 ++++++++++++++++++ 2 files changed, 252 insertions(+), 34 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Elasticsearch/Model/Adapter/ElasticsearchTest.php diff --git a/app/code/Magento/Elasticsearch/Model/Adapter/Elasticsearch.php b/app/code/Magento/Elasticsearch/Model/Adapter/Elasticsearch.php index 261f8d84b5baa..1b4b7ec322f3c 100644 --- a/app/code/Magento/Elasticsearch/Model/Adapter/Elasticsearch.php +++ b/app/code/Magento/Elasticsearch/Model/Adapter/Elasticsearch.php @@ -6,11 +6,18 @@ namespace Magento\Elasticsearch\Model\Adapter; -use Magento\Catalog\Api\Data\ProductAttributeInterface; +use Elasticsearch\Common\Exceptions\Missing404Exception; +use Magento\AdvancedSearch\Model\Client\ClientInterface; use Magento\Catalog\Api\ProductAttributeRepositoryInterface; use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\StaticField; +use Magento\Elasticsearch\Model\Adapter\Index\BuilderInterface; +use Magento\Elasticsearch\Model\Adapter\Index\IndexNameResolver; +use Magento\Elasticsearch\Model\Config; +use Magento\Elasticsearch\SearchAdapter\ConnectionManager; use Magento\Framework\App\ObjectManager; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Stdlib\ArrayManager; +use Psr\Log\LoggerInterface; /** * Elasticsearch adapter @@ -36,7 +43,7 @@ class Elasticsearch protected $connectionManager; /** - * @var \Magento\Elasticsearch\Model\Adapter\Index\IndexNameResolver + * @var IndexNameResolver */ protected $indexNameResolver; @@ -46,22 +53,22 @@ class Elasticsearch protected $fieldMapper; /** - * @var \Magento\Elasticsearch\Model\Config + * @var Config */ protected $clientConfig; /** - * @var \Magento\AdvancedSearch\Model\Client\ClientInterface + * @var ClientInterface */ protected $client; /** - * @var \Magento\Elasticsearch\Model\Adapter\Index\BuilderInterface + * @var BuilderInterface */ protected $indexBuilder; /** - * @var \Psr\Log\LoggerInterface + * @var LoggerInterface */ protected $logger; @@ -101,27 +108,27 @@ class Elasticsearch private $arrayManager; /** - * @param \Magento\Elasticsearch\SearchAdapter\ConnectionManager $connectionManager + * @param ConnectionManager $connectionManager * @param FieldMapperInterface $fieldMapper - * @param \Magento\Elasticsearch\Model\Config $clientConfig + * @param Config $clientConfig * @param Index\BuilderInterface $indexBuilder - * @param \Psr\Log\LoggerInterface $logger + * @param LoggerInterface $logger * @param Index\IndexNameResolver $indexNameResolver * @param BatchDataMapperInterface $batchDocumentDataMapper * @param array $options * @param ProductAttributeRepositoryInterface|null $productAttributeRepository * @param StaticField|null $staticFieldProvider * @param ArrayManager|null $arrayManager - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( - \Magento\Elasticsearch\SearchAdapter\ConnectionManager $connectionManager, + ConnectionManager $connectionManager, FieldMapperInterface $fieldMapper, - \Magento\Elasticsearch\Model\Config $clientConfig, - \Magento\Elasticsearch\Model\Adapter\Index\BuilderInterface $indexBuilder, - \Psr\Log\LoggerInterface $logger, - \Magento\Elasticsearch\Model\Adapter\Index\IndexNameResolver $indexNameResolver, + Config $clientConfig, + BuilderInterface $indexBuilder, + LoggerInterface $logger, + IndexNameResolver $indexNameResolver, BatchDataMapperInterface $batchDocumentDataMapper, $options = [], ProductAttributeRepositoryInterface $productAttributeRepository = null, @@ -146,7 +153,7 @@ public function __construct( $this->client = $this->connectionManager->getConnection($options); } catch (\Exception $e) { $this->logger->critical($e); - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('The search failed because of a search engine misconfiguration.') ); } @@ -156,14 +163,14 @@ public function __construct( * Retrieve Elasticsearch server status * * @return bool - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException */ public function ping() { try { $response = $this->client->ping(); } catch (\Exception $e) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('Could not ping search engine: %1', $e->getMessage()) ); } @@ -387,22 +394,12 @@ public function updateIndexMapping(int $storeId, string $mappedIndexerId, string return $this; } - $attribute = $this->productAttributeRepository->get($attributeCode); - $newAttributeMapping = $this->staticFieldProvider->getField($attribute); - $mappedAttributes = $this->getMappedAttributes($indexName); - - $attrToUpdate = array_diff_key($newAttributeMapping, $mappedAttributes); - if (!empty($attrToUpdate)) { - $settings['index']['mapping']['total_fields']['limit'] = $this - ->getMappingTotalFieldsLimit(array_merge($mappedAttributes, $attrToUpdate)); - $this->client->putIndexSettings($indexName, ['settings' => $settings]); - - $this->client->addFieldsMapping( - $attrToUpdate, - $indexName, - $this->clientConfig->getEntityType() - ); - $this->setMappedAttributes($indexName, $attrToUpdate); + try { + $this->updateMapping($attributeCode, $indexName); + } catch (Missing404Exception $e) { + unset($this->indexByCode[$mappedIndexerId . '_' . $storeId]); + $indexName = $this->getIndexFromAlias($storeId, $mappedIndexerId); + $this->updateMapping($attributeCode, $indexName); } return $this; @@ -505,4 +502,31 @@ private function getMappingTotalFieldsLimit(array $allAttributeTypes): int } return $count + self::MAPPING_TOTAL_FIELDS_BUFFER_LIMIT; } + + /** + * Perform index mapping update + * + * @param string $attributeCode + * @param string $indexName + * @return void + */ + private function updateMapping(string $attributeCode, string $indexName): void + { + $attribute = $this->productAttributeRepository->get($attributeCode); + $newAttributeMapping = $this->staticFieldProvider->getField($attribute); + $mappedAttributes = $this->getMappedAttributes($indexName); + $attrToUpdate = array_diff_key($newAttributeMapping, $mappedAttributes); + if (!empty($attrToUpdate)) { + $settings['index']['mapping']['total_fields']['limit'] = $this + ->getMappingTotalFieldsLimit(array_merge($mappedAttributes, $attrToUpdate)); + $this->client->putIndexSettings($indexName, ['settings' => $settings]); + + $this->client->addFieldsMapping( + $attrToUpdate, + $indexName, + $this->clientConfig->getEntityType() + ); + $this->setMappedAttributes($indexName, $attrToUpdate); + } + } } diff --git a/dev/tests/integration/testsuite/Magento/Elasticsearch/Model/Adapter/ElasticsearchTest.php b/dev/tests/integration/testsuite/Magento/Elasticsearch/Model/Adapter/ElasticsearchTest.php new file mode 100644 index 0000000000000..986d98f0f2f14 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Elasticsearch/Model/Adapter/ElasticsearchTest.php @@ -0,0 +1,194 @@ +objectManager = Bootstrap::getObjectManager(); + $this->indexNameResolver = $this->objectManager->get(IndexNameResolver::class); + $this->adapter = $this->objectManager->get(Elasticsearch::class); + $this->storeManager = $this->objectManager->create(StoreManagerInterface::class); + $connectionManager = $this->objectManager->create(ConnectionManager::class); + $this->client = $connectionManager->getConnection(); + $this->indexBuilder = $this->objectManager->get(BuilderInterface::class); + $this->arrayManager = $this->objectManager->get(ArrayManager::class); + $indexer = $this->objectManager->create(Indexer::class); + $indexer->load('catalogsearch_fulltext'); + $indexer->reindexAll(); + } + + /** + * @inheritdoc + */ + public function tearDown(): void + { + $this->deleteIndex($this->newIndex); + } + + /** + * Tests possibility to create mapping if adapter has obsolete index name in cache + * + * @magentoDataFixture Magento/Elasticsearch/_files/select_attribute.php + * @return void + */ + public function testRetryOnIndexNotFoundException(): void + { + $this->updateElasticsearchIndex(); + $this->createNewAttribute(); + $mapping = $this->client->getMapping(['index' => $this->newIndex]); + $pathField = $this->arrayManager->findPath('properties', $mapping); + $attributes = $this->arrayManager->get($pathField, $mapping, []); + $this->assertArrayHasKey('multiselect_attribute', $attributes); + } + + /** + * Prepare and save new attribute + * + * @return void + */ + public function createNewAttribute(): void + { + /** @var CategorySetup $installer */ + $installer = $this->objectManager->get(CategorySetup::class); + /** @var Attribute $attribute */ + $multiselectAttribute = $this->objectManager->get(Attribute::class); + $multiselectAttribute->setData( + [ + 'attribute_code' => 'multiselect_attribute', + 'entity_type_id' => $installer->getEntityTypeId('catalog_product'), + 'is_global' => 1, + 'is_user_defined' => 1, + 'frontend_input' => 'multiselect', + 'is_unique' => 0, + 'is_required' => 0, + 'is_searchable' => 1, + 'is_visible_in_advanced_search' => 0, + 'is_comparable' => 0, + 'is_filterable' => 1, + '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' => ['Multiselect Attribute'], + 'backend_type' => 'varchar', + 'backend_model' => ArrayBackend::class, + 'option' => [ + 'value' => [ + 'dog' => ['Dog'], + 'cat' => ['Cat'], + ], + 'order' => [ + 'dog' => 1, + 'cat' => 2, + ], + ], + ] + ); + $multiselectAttribute->save(); + } + + /** + * Prepare new index and delete old. Keep cache alive. + * + * @return void + */ + private function updateElasticsearchIndex(): void + { + $storeId = (int)$this->storeManager->getDefaultStoreView()->getId(); + $mappedIndexerId = 'product'; + $this->adapter->updateIndexMapping($storeId, $mappedIndexerId, 'select_attribute'); + $oldIndex = $this->indexNameResolver->getIndexFromAlias($storeId, $mappedIndexerId); + $this->newIndex = $oldIndex . '1'; + $this->deleteIndex($this->newIndex); + $this->indexBuilder->setStoreId($storeId); + $this->client->createIndex($this->newIndex, ['settings' => $this->indexBuilder->build()]); + $this->client->updateAlias( + $this->indexNameResolver->getIndexNameForAlias($storeId, $mappedIndexerId), + $this->newIndex, + $oldIndex + ); + $this->client->deleteIndex($oldIndex); + } + + /** + * Delete index by name if exists + * + * @param $newIndex + */ + private function deleteIndex($newIndex): void + { + if ($this->client->indexExists($newIndex)) { + $this->client->deleteIndex($newIndex); + } + } +} From 16629107cda62af80e601be6009a5f671e0107a1 Mon Sep 17 00:00:00 2001 From: engcom-Kilo Date: Tue, 17 Nov 2020 18:27:13 +0200 Subject: [PATCH 14/14] MC-37364: Unit Test and JSUnit Test fails to start on Magento composer 2.4.0. Revert integration tests suites. Add correct exception class to unit tests. --- .../Test/Unit/Model/ShippingInformationManagementTest.php | 3 ++- .../Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php | 3 ++- .../Test/Unit/Model/Checkout/Plugin/ValidationTest.php | 3 ++- .../Downloadable/Test/Unit/Model/Link/UpdateHandlerTest.php | 3 ++- .../Test/Unit/Model/Quote/Item/CartItemProcessorTest.php | 3 ++- .../Test/Unit/Model/Sample/UpdateHandlerTest.php | 3 ++- .../GiftMessage/Test/Unit/Model/Plugin/OrderGetTest.php | 5 +++-- .../GiftMessage/Test/Unit/Model/Plugin/OrderSaveTest.php | 5 +++-- .../Test/Unit/Model/DisableMultishippingTest.php | 3 ++- .../Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php | 2 +- .../Attribute/Media/ExternalVideoEntryConverterTest.php | 3 ++- .../Quote/Test/Unit/Model/ShippingAddressAssignmentTest.php | 3 ++- .../Magento/Sales/Test/Unit/Model/OrderRepositoryTest.php | 3 ++- dev/tests/integration/phpunit.xml.dist | 6 +++--- dev/tests/integration/testsuite/Magento/IntegrationTest.php | 2 +- 15 files changed, 31 insertions(+), 19 deletions(-) diff --git a/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php b/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php index 8bb017f4b212c..6ff782d94e4eb 100644 --- a/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Model/ShippingInformationManagementTest.php @@ -32,6 +32,7 @@ use Magento\Quote\Model\ShippingAssignmentFactory; use Magento\Quote\Model\ShippingFactory; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; /** @@ -631,7 +632,7 @@ private function getCartExtensionMock(): MockObject $mockBuilder = $this->getMockBuilder(CartExtension::class); try { $mockBuilder->addMethods(['getShippingAssignments', 'setShippingAssignments']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // CartExtension already generated. } diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php index 845d71f6e2f17..bb05d5636677c 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php @@ -20,6 +20,7 @@ use Magento\Quote\Api\Data\PaymentInterface; use Magento\Store\Model\ScopeInterface; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; /** @@ -174,7 +175,7 @@ private function getPaymentExtension(): MockObject $mockBuilder = $this->getMockBuilder(PaymentExtension::class); try { $mockBuilder->addMethods(['getAgreementIds']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // Payment extension already generated. } diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php index ebe4c2c1c7b05..b7e5127df1f8b 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php @@ -22,6 +22,7 @@ use Magento\Quote\Model\Quote; use Magento\Store\Model\ScopeInterface; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; /** @@ -241,7 +242,7 @@ private function getPaymentExtension(): MockObject $mockBuilder = $this->getMockBuilder(PaymentExtension::class); try { $mockBuilder->addMethods(['getAgreementIds']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // Payment extension already generated. } diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Link/UpdateHandlerTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Link/UpdateHandlerTest.php index af4d785955600..16b698adf57f0 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Model/Link/UpdateHandlerTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Model/Link/UpdateHandlerTest.php @@ -15,6 +15,7 @@ use Magento\Downloadable\Model\Link\UpdateHandler; use Magento\Downloadable\Model\Product\Type; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; /** @@ -157,7 +158,7 @@ private function getProductExtensionMock(): MockObject ->disableOriginalConstructor(); try { $mockBuilder->addMethods(['getDownloadableProductLinks']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // ProductExtension already generated. } diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php index 46ded7b3c456b..8eaed8eebc05a 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Model/Quote/Item/CartItemProcessorTest.php @@ -21,6 +21,7 @@ use Magento\Quote\Model\Quote\Item; use Magento\Quote\Model\Quote\ProductOptionFactory; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; /** @@ -250,7 +251,7 @@ private function getProductOptionExtensionMock(): MockObject $mockBuilder = $this->getMockBuilder(ProductOptionExtension::class); try { $mockBuilder->addMethods(['setDownloadableOption']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // ProductOptionExtension already generated. } diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Sample/UpdateHandlerTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Sample/UpdateHandlerTest.php index d826cde3cd78a..cc0427808ebc0 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Model/Sample/UpdateHandlerTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Model/Sample/UpdateHandlerTest.php @@ -15,6 +15,7 @@ use Magento\Downloadable\Model\Product\Type; use Magento\Downloadable\Model\Sample\UpdateHandler; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; /** @@ -157,7 +158,7 @@ private function getProductExtensionMock(): MockObject ->disableOriginalConstructor(); try { $mockBuilder->addMethods(['getDownloadableProductSamples']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // Product extension already generated. } diff --git a/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderGetTest.php b/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderGetTest.php index d9389f43843a3..85bae4a42a8df 100644 --- a/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderGetTest.php +++ b/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderGetTest.php @@ -20,6 +20,7 @@ use Magento\Sales\Api\Data\OrderItemInterface; use Magento\Sales\Model\ResourceModel\Order\Collection; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; /** @@ -279,7 +280,7 @@ private function getOrderExtensionMock(): MockObject $mockObject = $this->getMockBuilder(OrderExtension::class); try { $mockObject->addMethods(['getGiftMessage', 'setGiftMessage']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // Order extension already generated. } @@ -296,7 +297,7 @@ private function getOrderItemExtensionMock(): MockObject $mockObject = $this->getMockBuilder(OrderItemExtension::class); try { $mockObject->addMethods(['getGiftMessage', 'setGiftMessage']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // Order extension already generated. } diff --git a/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderSaveTest.php b/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderSaveTest.php index 11491754e3bcb..51702f4349003 100644 --- a/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderSaveTest.php +++ b/app/code/Magento/GiftMessage/Test/Unit/Model/Plugin/OrderSaveTest.php @@ -16,6 +16,7 @@ use Magento\Sales\Api\Data\OrderItemExtension; use Magento\Sales\Api\Data\OrderItemInterface; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; class OrderSaveTest extends TestCase @@ -199,7 +200,7 @@ private function getOrderExtensionMock(): MockObject $mockBuilder = $this->getMockBuilder(OrderExtension::class); try { $mockBuilder->addMethods(['getGiftMessage', 'setGiftMessage']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // OrderExtension already generated. } @@ -216,7 +217,7 @@ private function getOrderItemExtensionMock(): MockObject $mockBuilder = $this->getMockBuilder(OrderItemExtension::class); try { $mockBuilder->addMethods(['getGiftMessage', 'setGiftMessage']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // OrderItemExtension already generated. } diff --git a/app/code/Magento/Multishipping/Test/Unit/Model/DisableMultishippingTest.php b/app/code/Magento/Multishipping/Test/Unit/Model/DisableMultishippingTest.php index 075fc4ac347b0..8d4013dd54e2c 100644 --- a/app/code/Magento/Multishipping/Test/Unit/Model/DisableMultishippingTest.php +++ b/app/code/Magento/Multishipping/Test/Unit/Model/DisableMultishippingTest.php @@ -11,6 +11,7 @@ use Magento\Quote\Api\Data\CartExtensionInterface; use Magento\Quote\Api\Data\CartInterface; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; /** @@ -121,7 +122,7 @@ private function getCartExtensionMock(): MockObject ->disableOriginalConstructor(); try { $mockBuilder->addMethods(['getShippingAssignments', 'setShippingAssignments']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // CartExtension already generated. } diff --git a/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php b/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php index d6d80ab7de229..ece36673c1e82 100644 --- a/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php +++ b/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php @@ -392,7 +392,7 @@ private function getExtensionAttributesMock(): MockObject $extensionMockBuilder = $this->getMockBuilder(CartExtensionInterface::class); try { $extensionMockBuilder->addMethods(['setShippingAssignments']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // do nothing as CartExtensionInterface already generated and has 'setShippingAssignments' method. } diff --git a/app/code/Magento/ProductVideo/Test/Unit/Model/Product/Attribute/Media/ExternalVideoEntryConverterTest.php b/app/code/Magento/ProductVideo/Test/Unit/Model/Product/Attribute/Media/ExternalVideoEntryConverterTest.php index fd96ca7fb7ebf..a55416da4b532 100644 --- a/app/code/Magento/ProductVideo/Test/Unit/Model/Product/Attribute/Media/ExternalVideoEntryConverterTest.php +++ b/app/code/Magento/ProductVideo/Test/Unit/Model/Product/Attribute/Media/ExternalVideoEntryConverterTest.php @@ -20,6 +20,7 @@ use Magento\ProductVideo\Model\Product\Attribute\Media\ExternalVideoEntryConverter; use Magento\ProductVideo\Model\Product\Attribute\Media\VideoEntry; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; /** @@ -232,7 +233,7 @@ private function getProductAttributeMediaGalleryEntryExtensionMock(): MockObject 'getVideoContent', ] ); - } catch (\Exception $e) { + } catch (RuntimeException $e) { // ProductAttributeMediaGalleryEntryExtension already generated and has all necessary methods. } diff --git a/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressAssignmentTest.php b/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressAssignmentTest.php index 75f3af2643722..868188c97b1fa 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressAssignmentTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/ShippingAddressAssignmentTest.php @@ -16,6 +16,7 @@ use Magento\Quote\Model\Quote\ShippingAssignment\ShippingAssignmentProcessor; use Magento\Quote\Model\ShippingAddressAssignment; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; class ShippingAddressAssignmentTest extends TestCase @@ -122,7 +123,7 @@ private function getCartExtensionMock(): MockObject $mockBuilder = $this->getMockBuilder(CartExtension::class); try { $mockBuilder->addMethods(['setShippingAssignments']); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // CartExtension already generated. } diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderRepositoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderRepositoryTest.php index d242268649a5e..41c92da1cde5d 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderRepositoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderRepositoryTest.php @@ -29,6 +29,7 @@ use Magento\Tax\Api\Data\OrderTaxDetailsInterface; use Magento\Tax\Api\OrderTaxManagementInterface; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\RuntimeException; use PHPUnit\Framework\TestCase; /** @@ -261,7 +262,7 @@ private function getOrderExtensionMock(): MockObject 'setPaymentAdditionalInfo', ] ); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { // Order extension already generated. } diff --git a/dev/tests/integration/phpunit.xml.dist b/dev/tests/integration/phpunit.xml.dist index d57e6809da7e9..92dd1e11f613b 100644 --- a/dev/tests/integration/phpunit.xml.dist +++ b/dev/tests/integration/phpunit.xml.dist @@ -17,14 +17,14 @@ > - + testsuite/Magento/IntegrationTest.php - + testsuite/Magento/MemoryUsageTest.php - + testsuite ../../../app/code/*/*/Test/Integration testsuite/Magento/MemoryUsageTest.php diff --git a/dev/tests/integration/testsuite/Magento/IntegrationTest.php b/dev/tests/integration/testsuite/Magento/IntegrationTest.php index 39d383fb86354..26dec49c83b52 100644 --- a/dev/tests/integration/testsuite/Magento/IntegrationTest.php +++ b/dev/tests/integration/testsuite/Magento/IntegrationTest.php @@ -41,7 +41,7 @@ public static function suite($className) $suitesConfig = $configuration->testSuite(); $suite = new TestSuite(); foreach ($suitesConfig as $suiteConfig) { - if ($suiteConfig->name() === 'Magento_Integration_Tests') { + if ($suiteConfig->name() === 'Magento Integration Tests') { continue; } $suites = self::getSuites($suiteConfig);