From 6f1e2e7b0481933f35f4e6def35b63ad2b3ffc8e Mon Sep 17 00:00:00 2001 From: Roman Zhupanyn Date: Fri, 6 Mar 2020 13:02:32 +0200 Subject: [PATCH 1/8] MC-32126: Admin: Create/update/delete customer --- .../Controller/Adminhtml/Index/DeleteTest.php | 104 ++++ .../Controller/Adminhtml/Index/SaveTest.php | 584 ++++++++++++++++++ .../Adminhtml/Index/ValidateTest.php | 123 ++++ .../Controller/Adminhtml/IndexTest.php | 347 +---------- .../AccountManagement/CreateAccountTest.php | 398 +++++++++++- .../Model/AccountManagement/ValidateTest.php | 113 ++++ .../Customer/Model/AccountManagementTest.php | 330 ---------- 7 files changed, 1327 insertions(+), 672 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/DeleteTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/SaveTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/ValidateTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/ValidateTest.php diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/DeleteTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/DeleteTest.php new file mode 100644 index 0000000000000..1f40c459c43e0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/DeleteTest.php @@ -0,0 +1,104 @@ +formKey = $this->_objectManager->get(FormKey::class); + } + + /** + * Delete customer + * + * @dataProvider deleteCustomerProvider + * @magentoDataFixture Magento/Customer/_files/customer_sample.php + * + * @param array $paramsData + * @param string $expected + * @return void + */ + public function testDeleteCustomer(array $paramsData, array $expected): void + { + $this->dispatchCustomerDelete($paramsData); + + $this->assertRedirect($this->stringContains('customer/index')); + $this->assertSessionMessages( + $this->equalTo([(string)__(...$expected['message'])]), + $expected['message_type'] + ); + } + + /** + * Delete customer provider + * + * @return array + */ + public function deleteCustomerProvider(): array + { + return [ + 'delete_customer_success' => [ + 'params_data' => [ + 'id' => 1, + ], + 'expected' => [ + 'message' => ['You deleted the customer.'], + 'message_type' => MessageInterface::TYPE_SUCCESS, + ], + ], + 'not_existing_customer_error' => [ + 'params_data' => [ + 'id' => 2, + ], + 'expected' => [ + 'message' => [ + 'No such entity with %fieldName = %fieldValue', + [ + 'fieldName' => 'customerId', + 'fieldValue' => '2', + ], + ], + 'message_type' => MessageInterface::TYPE_ERROR, + ], + ], + ]; + } + + /** + * Delete customer using backend/customer/index/delete action. + * + * @param array $params + * @return void + */ + private function dispatchCustomerDelete(array $params): void + { + $params['form_key'] = $this->formKey->getFormKey(); + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $this->getRequest()->setParams($params); + $this->dispatch('backend/customer/index/delete'); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/SaveTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/SaveTest.php new file mode 100644 index 0000000000000..aed6003ea76ac --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/SaveTest.php @@ -0,0 +1,584 @@ +customerRepository = $this->_objectManager->get(CustomerRepositoryInterface::class); + $this->customerViewHelper = $this->_objectManager->get(CustomerNameGenerationInterface::class); + $this->subscriberFactory = $this->_objectManager->get(SubscriberFactory::class); + $this->session = $this->_objectManager->get(Session::class); + $this->storeManager = $this->_objectManager->get(StoreManagerInterface::class); + } + + /** + * Create customer + * + * @dataProvider createCustomerProvider + * @magentoDbIsolation enabled + * + * @param array $postData + * @param array $expectedData + * @return void + */ + public function testCreateCustomer(array $postData, array $expectedData): void + { + $this->dispatchCustomerSave($postData); + $this->assertSessionMessages( + $this->equalTo([(string)__('You saved the customer.')]), + MessageInterface::TYPE_SUCCESS + ); + $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'index/key/')); + $this->assertCustomerData( + $postData['customer'][CustomerData::EMAIL], + (int)$postData['customer'][CustomerData::WEBSITE_ID], + $expectedData + ); + } + + /** + * Create customer provider + * + * @return array + */ + public function createCustomerProvider(): array + { + $defaultCustomerData = $this->getDefaultCustomerData(); + $expectedCustomerData = $this->getExpectedCustomerData($defaultCustomerData); + return [ + "fill_all_fields" => [ + 'post_data' => $defaultCustomerData, + 'expected_data' => $expectedCustomerData + ], + 'only_require_fields' => [ + 'post_data' => array_replace_recursive( + $defaultCustomerData, + [ + 'customer' => [ + CustomerData::DISABLE_AUTO_GROUP_CHANGE => '0', + CustomerData::PREFIX => '', + CustomerData::MIDDLENAME => '', + CustomerData::SUFFIX => '', + CustomerData::DOB => '', + CustomerData::TAXVAT => '', + CustomerData::GENDER => '', + ], + ] + ), + 'expected_data' => array_replace_recursive( + $expectedCustomerData, + [ + 'customer' => [ + CustomerData::DISABLE_AUTO_GROUP_CHANGE => '0', + CustomerData::PREFIX => '', + CustomerData::MIDDLENAME => '', + CustomerData::SUFFIX => '', + CustomerData::DOB => '', + CustomerData::TAXVAT => '', + CustomerData::GENDER => '0', + ], + ] + ), + ], + ]; + } + + /** + * Create customer with exceptions + * + * @dataProvider createCustomerErrorsProvider + * @magentoDbIsolation enabled + * + * @param array $postData + * @param array $expectedData + * @param array $expectedMessage + * @return void + */ + public function testCreateCustomerErrors(array $postData, array $expectedData, array $expectedMessage): void + { + $this->dispatchCustomerSave($postData); + $this->assertSessionMessages( + $this->equalTo($expectedMessage), + MessageInterface::TYPE_ERROR + ); + $this->assertNotEmpty($this->session->getCustomerFormData()); + $this->assertArraySubset($expectedData, $this->session->getCustomerFormData()); + $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'new/key/')); + } + + /** + * Create customer errors provider + * + * @return array + */ + public function createCustomerErrorsProvider(): array + { + $defaultCustomerData = $this->getDefaultCustomerData(); + return [ + 'without_some_require_fields' => [ + 'post_data' => array_replace_recursive( + $defaultCustomerData, + [ + 'customer' => [ + CustomerData::FIRSTNAME => '', + CustomerData::LASTNAME => '', + ], + ] + ), + 'expected_data' => array_replace_recursive( + $defaultCustomerData, + [ + 'customer' => [ + CustomerData::FIRSTNAME => '', + CustomerData::LASTNAME => '', + CustomerData::DOB => '2000-01-01', + ], + ] + ), + 'expected_message' => [ + (string)__('"%1" is a required value.', 'First Name'), + (string)__('"%1" is a required value.', 'Last Name'), + ], + ], + 'with_empty_post_data' => [ + 'post_data' => [], + 'expected_data' => [], + 'expected_message' => [ + (string)__('The customer email is missing. Enter and try again.'), + ], + ], + 'with_invalid_form_data' => [ + 'post_data' => [ + 'account' => [ + 'middlename' => 'test middlename', + 'group_id' => 1, + ], + ], + 'expected_data' => [ + 'account' => [ + 'middlename' => 'test middlename', + 'group_id' => 1, + ], + ], + 'expected_message' => [ + (string)__('The customer email is missing. Enter and try again.'), + ], + ] + ]; + } + + /** + * Update customer with subscription and redirect to edit page. + * + * @magentoDataFixture Magento/Store/_files/core_fixturestore.php + * @magentoDataFixture Magento/Customer/_files/customer.php + * @return void + */ + public function testUpdateCustomer(): void + { + /** @var CustomerData $customerData */ + $customerData = $this->customerRepository->getById(1); + $secondStore = $this->storeManager->getStore('fixturestore'); + $postData = $expectedData = [ + 'customer' => [ + CustomerData::FIRSTNAME => 'Jane', + CustomerData::MIDDLENAME => 'Mdl', + CustomerData::LASTNAME => 'Doe', + ], + 'subscription_status' => [$customerData->getWebsiteId() => '1'], + 'subscription_store' => [$customerData->getWebsiteId() => $secondStore->getId()], + ]; + $postData['customer']['entity_id'] = $customerData->getId(); + $params = ['back' => true]; + + $this->dispatchCustomerSave($postData, $params); + $this->assertSessionMessages( + $this->equalTo([(string)__('You saved the customer.')]), + MessageInterface::TYPE_SUCCESS + ); + $this->assertRedirect($this->stringStartsWith( + $this->_baseControllerUrl . 'edit/id/' . $customerData->getId() + )); + $this->assertCustomerData($customerData->getEmail(), (int)$customerData->getWebsiteId(), $expectedData); + $this->assertCustomerSubscription( + (int)$customerData->getId(), + (int)$customerData->getWebsiteId(), + Subscriber::STATUS_SUBSCRIBED, + (int)$secondStore->getId() + ); + } + + /** + * @magentoDataFixture Magento/Newsletter/_files/subscribers.php + * @return void + */ + public function testExistingCustomerUnsubscribeNewsletter(): void + { + /** @var CustomerData $customerData */ + $customerData = $this->customerRepository->getById(1); + /** @var Store $defaultStore */ + $defaultStore = $this->storeManager->getWebsite()->getDefaultStore(); + $postData = [ + 'customer' => [ + 'entity_id' => $customerData->getId(), + CustomerData::EMAIL => 'customer@example.com', + CustomerData::FIRSTNAME => 'test firstname', + CustomerData::LASTNAME => 'test lastname', + 'sendemail_store_id' => '1' + ], + 'subscription_status' => [$customerData->getWebsiteId() => '0'], + 'subscription_store' => [$customerData->getWebsiteId() => $defaultStore->getId()], + ]; + $this->dispatchCustomerSave($postData); + $this->assertSessionMessages( + $this->equalTo([(string)__('You saved the customer.')]), + MessageInterface::TYPE_SUCCESS + ); + $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'index/key/')); + $this->assertCustomerSubscription( + (int)$customerData->getId(), + (int)$customerData->getWebsiteId(), + Subscriber::STATUS_UNSUBSCRIBED, + (int)$defaultStore->getId() + ); + } + + /** + * Ensure that an email is sent during save action + * + * @magentoConfigFixture current_store customer/account_information/change_email_template change_email_template + * @magentoConfigFixture current_store customer/password/forgot_email_identity support + * @magentoDataFixture Magento/Customer/_files/customer_sample.php + * @return void + */ + public function testExistingCustomerChangeEmail(): void + { + $customerId = 1; + $newEmail = 'newcustomer@example.com'; + $transportBuilderMock = $this->prepareEmailMock( + 2, + 'change_email_template', + [ + 'name' => 'CustomerSupport', + 'email' => 'support@example.com', + ], + $customerId, + $newEmail + ); + $this->addEmailMockToClass($transportBuilderMock, EmailNotification::class); + $postData = [ + 'customer' => [ + 'entity_id' => $customerId, + CustomerData::WEBSITE_ID => '1', + CustomerData::GROUP_ID => '1', + CustomerData::FIRSTNAME => 'test firstname', + CustomerData::MIDDLENAME => 'test middlename', + CustomerData::LASTNAME => 'test lastname', + CustomerData::EMAIL => $newEmail, + 'new_password' => 'auto', + 'sendemail_store_id' => '1', + 'sendemail' => '1', + CustomerData::CREATED_AT => '2000-01-01 00:00:00', + CustomerData::DEFAULT_SHIPPING => '_item1', + CustomerData::DEFAULT_BILLING => '1' + ] + ]; + $this->dispatchCustomerSave($postData); + + /** + * Check that no errors were generated and set to session + */ + $this->assertSessionMessages($this->isEmpty(), MessageInterface::TYPE_ERROR); + $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'index/key/')); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer_sample.php + * @return void + */ + public function testCreateSameEmailFormatDateError(): void + { + $postData = [ + 'customer' => [ + CustomerData::WEBSITE_ID => '1', + CustomerData::FIRSTNAME => 'test firstname', + CustomerData::MIDDLENAME => 'test middlename', + CustomerData::LASTNAME => 'test lastname', + CustomerData::EMAIL => 'customer@example.com', + CustomerData::DOB => '12/3/1996', + ], + ]; + $postFormatted = array_replace_recursive( + $postData, + [ + 'customer' => [ + CustomerData::DOB => '1996-12-03', + ], + ] + ); + $this->dispatchCustomerSave($postData); + $this->assertSessionMessages( + $this->equalTo([ + (string)__('A customer with the same email address already exists in an associated website.'), + ]), + MessageInterface::TYPE_ERROR + ); + $this->assertArraySubset( + $postFormatted, + $this->session->getCustomerFormData(), + true, + 'Customer form data should be formatted' + ); + $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'new/key/')); + } + + /** + * Default values for customer creation + * + * @return array + */ + private function getDefaultCustomerData(): array + { + return [ + 'customer' => [ + CustomerData::WEBSITE_ID => '1', + CustomerData::GROUP_ID => '1', + CustomerData::DISABLE_AUTO_GROUP_CHANGE => '1', + CustomerData::PREFIX => 'Mr.', + CustomerData::FIRSTNAME => 'Jane', + CustomerData::MIDDLENAME => 'Mdl', + CustomerData::LASTNAME => 'Doe', + CustomerData::SUFFIX => 'Esq.', + CustomerData::EMAIL => 'janedoe' . uniqid() . '@example.com', + CustomerData::DOB => '01/01/2000', + CustomerData::TAXVAT => '121212', + CustomerData::GENDER => 'Male', + 'sendemail_store_id' => '1', + ] + ]; + } + + /** + * Expected values for customer creation + * + * @param array $defaultCustomerData + * @return array + */ + private function getExpectedCustomerData(array $defaultCustomerData): array + { + unset($defaultCustomerData['customer']['sendemail_store_id']); + return array_replace_recursive( + $defaultCustomerData, + [ + 'customer' => [ + CustomerData::DOB => '2000-01-01', + CustomerData::GENDER => '0', + CustomerData::STORE_ID => 1, + CustomerData::CREATED_IN => 'Default Store View', + ], + ] + ); + } + + /** + * Create or update customer using backend/customer/index/save action. + * + * @param array $postData + * @param array $params + * @return void + */ + private function dispatchCustomerSave(array $postData, array $params = []): void + { + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $this->getRequest()->setPostValue($postData); + if (!empty($params)) { + $this->getRequest()->setParams($params); + } + $this->dispatch('backend/customer/index/save'); + } + + /** + * Check that customer parameters match expected values. + * + * @param string $customerEmail + * @param int $customerWebsiteId + * @param array $expectedData + * @return void + */ + private function assertCustomerData( + string $customerEmail, + int $customerWebsiteId, + array $expectedData + ): void { + /** @var CustomerData $customerData */ + $customerData = $this->customerRepository->get($customerEmail, $customerWebsiteId); + $actualCustomerArray = $customerData->__toArray(); + foreach ($expectedData['customer'] as $key => $expectedValue) { + $this->assertEquals( + $expectedValue, + $actualCustomerArray[$key], + "Invalid expected value for $key field." + ); + } + } + + /** + * Check that customer subscription status match expected status. + * + * @param int $customerId + * @param int $websiteId + * @param int $expectedStatus + * @param int $expectedStoreId + * @return void + */ + private function assertCustomerSubscription( + int $customerId, + int $websiteId, + int $expectedStatus, + int $expectedStoreId + ): void { + $subscriber = $this->subscriberFactory->create(); + $subscriber->loadByCustomer($customerId, $websiteId); + $this->assertNotEmpty($subscriber->getId()); + $this->assertEquals($expectedStatus, $subscriber->getStatus()); + $this->assertEquals($expectedStoreId, $subscriber->getStoreId()); + } + + /** + * Prepare email mock to test emails. + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * @param int $occurrenceNumber + * @param string $templateId + * @param array $sender + * @param int $customerId + * @param string|null $newEmail + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function prepareEmailMock( + int $occurrenceNumber, + string $templateId, + array $sender, + int $customerId, + $newEmail = null + ) : \PHPUnit_Framework_MockObject_MockObject { + $area = Area::AREA_FRONTEND; + $customer = $this->customerRepository->getById($customerId); + $storeId = $customer->getStoreId(); + $name = $this->customerViewHelper->getCustomerName($customer); + + $transportMock = $this->getMockBuilder(TransportInterface::class) + ->setMethods(['sendMessage']) + ->getMockForAbstractClass(); + $transportMock->expects($this->exactly($occurrenceNumber)) + ->method('sendMessage'); + $transportBuilderMock = $this->getMockBuilder(TransportBuilder::class) + ->disableOriginalConstructor() + ->setMethods( + [ + 'addTo', + 'setFrom', + 'setTemplateIdentifier', + 'setTemplateVars', + 'setTemplateOptions', + 'getTransport', + ] + ) + ->getMock(); + $transportBuilderMock->method('setTemplateIdentifier') + ->with($templateId) + ->willReturnSelf(); + $transportBuilderMock->method('setTemplateOptions') + ->with(['area' => $area, 'store' => $storeId]) + ->willReturnSelf(); + $transportBuilderMock->method('setTemplateVars') + ->willReturnSelf(); + $transportBuilderMock->method('setFrom') + ->with($sender) + ->willReturnSelf(); + $transportBuilderMock->method('addTo') + ->with($this->logicalOr($customer->getEmail(), $newEmail), $name) + ->willReturnSelf(); + $transportBuilderMock->expects($this->exactly($occurrenceNumber)) + ->method('getTransport') + ->willReturn($transportMock); + + return $transportBuilderMock; + } + + /** + * Add email mock to class + * + * @param \PHPUnit_Framework_MockObject_MockObject $transportBuilderMock + * @param string $className + * @return void + */ + private function addEmailMockToClass( + \PHPUnit_Framework_MockObject_MockObject $transportBuilderMock, + $className + ): void { + $mocked = $this->_objectManager->create( + $className, + ['transportBuilder' => $transportBuilderMock] + ); + $this->_objectManager->addSharedInstance( + $mocked, + $className + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/ValidateTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/ValidateTest.php new file mode 100644 index 0000000000000..d42132823d3da --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/ValidateTest.php @@ -0,0 +1,123 @@ +jsonSerializer = $this->_objectManager->get(SerializerInterface::class); + } + + /** + * Validate customer with exception + * + * @magentoDbIsolation enabled + * @return void + */ + public function testValidateCustomerErrors(): void + { + $postData = [ + 'customer' => [], + ]; + $attributeEmptyMessage = 'The "%1" attribute value is empty. Set the attribute and try again.'; + $expectedErrors = [ + 'error' => true, + 'messages' => [ + (string)__($attributeEmptyMessage, 'First Name'), + (string)__($attributeEmptyMessage, 'Last Name'), + (string)__($attributeEmptyMessage, 'Email'), + ], + ]; + + $this->dispatchCustomerValidate($postData); + $errors = $this->jsonSerializer->unserialize($this->getResponse()->getBody()); + $this->assertEquals($expectedErrors, $errors); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Customer/_files/customer_address.php + * @return void + */ + public function testValidateCustomerWithAddressSuccess(): void + { + $customerData = [ + 'customer' => [ + 'entity_id' => '1', + 'middlename' => 'new middlename', + 'group_id' => 1, + 'website_id' => 1, + 'firstname' => 'new firstname', + 'lastname' => 'new lastname', + 'email' => 'example@domain.com', + 'default_shipping' => '_item1', + 'new_password' => 'auto', + 'sendemail_store_id' => '1', + 'sendemail' => '1', + ], + 'address' => [ + '_item1' => [ + 'firstname' => 'update firstname', + 'lastname' => 'update lastname', + 'street' => ['update street'], + 'city' => 'update city', + 'country_id' => 'US', + 'region_id' => 10, + 'postcode' => '01001', + 'telephone' => '+7000000001', + ], + '_template_' => [ + 'firstname' => '', + 'lastname' => '', + 'street' => [], + 'city' => '', + 'country_id' => 'US', + 'postcode' => '', + 'telephone' => '', + ], + ], + ]; + $this->dispatchCustomerValidate($customerData); + + $this->assertSessionMessages($this->isEmpty(), MessageInterface::TYPE_ERROR); + $errors = $this->jsonSerializer->unserialize($this->getResponse()->getBody()); + $this->assertEquals(['error' => 0], $errors); + } + + /** + * Validate customer using backend/customer/index/validate action. + * + * @param array $postData + * @return void + */ + private function dispatchCustomerValidate(array $postData): void + { + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $this->getRequest()->setPostValue($postData); + $this->dispatch('backend/customer/index/validate'); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php index 4a7cc7591f7aa..756270344d720 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php @@ -6,19 +6,19 @@ namespace Magento\Customer\Controller\Adminhtml; -use Magento\Customer\Api\AccountManagementInterface; -use Magento\Customer\Api\AddressRepositoryInterface; +use Magento\Backend\Model\Session; use Magento\Customer\Api\CustomerRepositoryInterface; -use Magento\Customer\Controller\RegistryConstants; +use Magento\Customer\Helper\View; use Magento\Customer\Model\EmailNotification; use Magento\TestFramework\Helper\Bootstrap; use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\TestFramework\TestCase\AbstractBackendController; /** * @magentoAppArea adminhtml * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class IndexTest extends \Magento\TestFramework\TestCase\AbstractBackendController +class IndexTest extends AbstractBackendController { /** * Base controller URL @@ -30,21 +30,9 @@ class IndexTest extends \Magento\TestFramework\TestCase\AbstractBackendControlle /** @var CustomerRepositoryInterface */ protected $customerRepository; - /** @var AddressRepositoryInterface */ - protected $addressRepository; - - /** @var AccountManagementInterface */ - protected $accountManagement; - - /** @var \Magento\Framework\Data\Form\FormKey */ - protected $formKey; - - /**@var \Magento\Customer\Helper\View */ + /** @var View */ protected $customerViewHelper; - /** @var \Magento\TestFramework\ObjectManager */ - protected $objectManager; - /** * @inheritDoc */ @@ -52,23 +40,8 @@ protected function setUp() { parent::setUp(); $this->_baseControllerUrl = 'http://localhost/index.php/backend/customer/index/'; - $this->customerRepository = Bootstrap::getObjectManager()->get( - \Magento\Customer\Api\CustomerRepositoryInterface::class - ); - $this->addressRepository = Bootstrap::getObjectManager()->get( - \Magento\Customer\Api\AddressRepositoryInterface::class - ); - $this->accountManagement = Bootstrap::getObjectManager()->get( - \Magento\Customer\Api\AccountManagementInterface::class - ); - $this->formKey = Bootstrap::getObjectManager()->get( - \Magento\Framework\Data\Form\FormKey::class - ); - - $this->objectManager = Bootstrap::getObjectManager(); - $this->customerViewHelper = $this->objectManager->get( - \Magento\Customer\Helper\View::class - ); + $this->customerRepository = $this->_objectManager->get(CustomerRepositoryInterface::class); + $this->customerViewHelper = $this->_objectManager->get(View::class); } /** @@ -79,144 +52,12 @@ protected function tearDown() /** * Unset customer data */ - Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->setCustomerData(null); + $this->_objectManager->get(Session::class)->setCustomerData(null); /** * Unset messages */ - Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->getMessages(true); - } - - /** - * @magentoDbIsolation enabled - */ - public function testSaveActionWithEmptyPostData() - { - $this->getRequest()->setPostValue([])->setMethod(HttpRequest::METHOD_POST); - $this->dispatch('backend/customer/index/save'); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl)); - } - - /** - * @magentoDbIsolation enabled - */ - public function testSaveActionWithInvalidFormData() - { - $post = ['account' => ['middlename' => 'test middlename', 'group_id' => 1]]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - $this->dispatch('backend/customer/index/save'); - /** - * Check that errors was generated and set to session - */ - $this->assertSessionMessages( - $this->logicalNot($this->isEmpty()), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR - ); - /** @var \Magento\Backend\Model\Session $session */ - $session = $this->objectManager->get(\Magento\Backend\Model\Session::class); - /** - * Check that customer data were set to session - */ - $this->assertNotEmpty($session->getCustomerFormData()); - $this->assertArraySubset($post, $session->getCustomerFormData()); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'new')); - } - - /** - * @magentoDataFixture Magento/Newsletter/_files/subscribers.php - */ - public function testSaveActionExistingCustomerUnsubscribeNewsletter() - { - $customerId = 1; - $websiteId = 1; - - /** @var \Magento\Newsletter\Model\Subscriber $subscriber */ - $subscriber = $this->objectManager->get(\Magento\Newsletter\Model\SubscriberFactory::class)->create(); - $this->assertEmpty($subscriber->getId()); - $subscriber->loadByCustomerId($customerId); - $this->assertNotEmpty($subscriber->getId()); - $this->assertEquals(1, $subscriber->getStatus()); - - $post = [ - 'customer' => [ - 'entity_id' => $customerId, - 'email' => 'customer@example.com', - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'sendemail_store_id' => 1 - ], - 'subscription_status' => [$websiteId => '0'] - ]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - $this->getRequest()->setParam('id', 1); - $this->dispatch('backend/customer/index/save'); - - /** @var \Magento\Newsletter\Model\Subscriber $subscriber */ - $subscriber = $this->objectManager->get(\Magento\Newsletter\Model\SubscriberFactory::class)->create(); - $this->assertEmpty($subscriber->getId()); - $subscriber->loadByCustomerId($customerId); - $this->assertNotEmpty($subscriber->getId()); - $this->assertEquals(3, $subscriber->getStatus()); - - /** - * Check that success message is set - */ - $this->assertSessionMessages( - $this->equalTo(['You saved the customer.']), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'index/key/')); - } - - /** - * Ensure that an email is sent during save action - * - * @magentoConfigFixture current_store customer/account_information/change_email_template change_email_template - * @magentoConfigFixture current_store customer/password/forgot_email_identity support - * @magentoDataFixture Magento/Customer/_files/customer_sample.php - */ - public function testSaveActionExistingCustomerChangeEmail() - { - $customerId = 1; - $newEmail = 'newcustomer@example.com'; - $transportBuilderMock = $this->prepareEmailMock( - 2, - 'change_email_template', - [ - 'name' => 'CustomerSupport', - 'email' => 'support@example.com', - ], - $customerId, - $newEmail - ); - $this->addEmailMockToClass($transportBuilderMock, EmailNotification::class); - $post = [ - 'customer' => [ - 'entity_id' => $customerId, - 'middlename' => 'test middlename', - 'group_id' => 1, - 'website_id' => 1, - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'email' => $newEmail, - 'new_password' => 'auto', - 'sendemail_store_id' => '1', - 'sendemail' => '1', - 'created_at' => '2000-01-01 00:00:00', - 'default_shipping' => '_item1', - 'default_billing' => 1, - ] - ]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - $this->getRequest()->setParam('id', 1); - $this->dispatch('backend/customer/index/save'); - - /** - * Check that no errors were generated and set to session - */ - $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'index/key/')); + $this->_objectManager->get(Session::class)->getMessages(true); } /** @@ -265,83 +106,6 @@ public function testInlineEditChangeEmail() $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); } - /** - * @magentoDataFixture Magento/Customer/_files/customer_sample.php - */ - public function testSaveActionCoreException() - { - $post = [ - 'customer' => [ - 'middlename' => 'test middlename', - 'group_id' => 1, - 'website_id' => 1, - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'email' => 'customer@example.com', - 'password' => 'password', - ], - ]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - $this->dispatch('backend/customer/index/save'); - /* - * Check that error message is set - */ - $this->assertSessionMessages( - $this->equalTo(['A customer with the same email address already exists in an associated website.']), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR - ); - $this->assertArraySubset( - $post, - Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->getCustomerFormData() - ); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'new/key/')); - } - - /** - * @magentoDataFixture Magento/Customer/_files/customer_sample.php - */ - public function testSaveActionCoreExceptionFormatFormData() - { - $post = [ - 'customer' => [ - 'middlename' => 'test middlename', - 'website_id' => 1, - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'email' => 'customer@example.com', - 'dob' => '12/3/1996', - ], - ]; - $postCustomerFormatted = [ - 'middlename' => 'test middlename', - 'website_id' => 1, - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'email' => 'customer@example.com', - 'dob' => '1996-12-03', - ]; - - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - $this->dispatch('backend/customer/index/save'); - /* - * Check that error message is set - */ - $this->assertSessionMessages( - $this->equalTo(['A customer with the same email address already exists in an associated website.']), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR - ); - - $customerFormData = Bootstrap::getObjectManager() - ->get(\Magento\Backend\Model\Session::class) - ->getCustomerFormData(); - $this->assertEquals( - $postCustomerFormatted, - $customerFormData['customer'], - 'Customer form data should be formatted' - ); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'new/key/')); - } - /** * @magentoDataFixture Magento/Customer/_files/customer_sample.php */ @@ -390,42 +154,6 @@ public function te1stNewActionWithCustomerData() $this->testNewAction(); } - /** - * @magentoDataFixture Magento/Customer/_files/customer_sample.php - */ - public function testDeleteAction() - { - $this->getRequest()->setParam('id', 1); - $this->getRequest()->setParam('form_key', $this->formKey->getFormKey()); - - $this->getRequest()->setMethod(\Zend\Http\Request::METHOD_POST); - - $this->dispatch('backend/customer/index/delete'); - $this->assertRedirect($this->stringContains('customer/index')); - $this->assertSessionMessages( - $this->equalTo(['You deleted the customer.']), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - } - - /** - * @magentoDataFixture Magento/Customer/_files/customer_sample.php - */ - public function testNotExistingCustomerDeleteAction() - { - $this->getRequest()->setParam('id', 2); - $this->getRequest()->setParam('form_key', $this->formKey->getFormKey()); - - $this->getRequest()->setMethod(\Zend\Http\Request::METHOD_POST); - - $this->dispatch('backend/customer/index/delete'); - $this->assertRedirect($this->stringContains('customer/index')); - $this->assertSessionMessages( - $this->equalTo(['No such entity with customerId = 2']), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR - ); - } - /** * @magentoDataFixture Magento/Customer/_files/customer_sample.php */ @@ -437,63 +165,6 @@ public function testCartAction() $this->assertContains('
[ - 'entity_id' => '1', - 'middlename' => 'new middlename', - 'group_id' => 1, - 'website_id' => 1, - 'firstname' => 'new firstname', - 'lastname' => 'new lastname', - 'email' => 'example@domain.com', - 'default_shipping' => '_item1', - 'new_password' => 'auto', - 'sendemail_store_id' => '1', - 'sendemail' => '1', - ], - 'address' => [ - '_item1' => [ - 'firstname' => 'update firstname', - 'lastname' => 'update lastname', - 'street' => ['update street'], - 'city' => 'update city', - 'country_id' => 'US', - 'region_id' => 10, - 'postcode' => '01001', - 'telephone' => '+7000000001', - ], - '_template_' => [ - 'firstname' => '', - 'lastname' => '', - 'street' => [], - 'city' => '', - 'country_id' => 'US', - 'postcode' => '', - 'telephone' => '', - ], - ], - ]; - /** - * set customer data - */ - $this->getRequest()->setParams($customerData)->setMethod(HttpRequest::METHOD_POST); - $this->dispatch('backend/customer/index/validate'); - $body = $this->getResponse()->getBody(); - - /** - * Check that no errors were generated and set to session - */ - $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); - - $this->assertEquals('{"error":0}', $body); - } - /** * @magentoDbIsolation enabled */ diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountTest.php index 03473e9247c51..8be3dfc10d86e 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountTest.php @@ -8,22 +8,31 @@ namespace Magento\Customer\Model\AccountManagement; use Magento\Customer\Api\AccountManagementInterface; +use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Customer\Api\Data\CustomerInterface; use Magento\Customer\Api\Data\CustomerInterfaceFactory; +use Magento\Customer\Model\Customer; +use Magento\Customer\Model\CustomerFactory; use Magento\Framework\Api\DataObjectHelper; +use Magento\Framework\Api\ExtensibleDataObjectConverter; +use Magento\Framework\Api\SimpleDataObjectConverter; +use Magento\Framework\Encryption\EncryptorInterface; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Math\Random; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Validator\Exception; +use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Xpath; +use Magento\TestFramework\Mail\Template\TransportBuilderMock; use PHPUnit\Framework\TestCase; /** * Tests for customer creation via customer account management service. * - * @magentoAppArea frontend * @magentoDbIsolation enabled + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class CreateAccountTest extends TestCase { @@ -56,6 +65,41 @@ class CreateAccountTest extends TestCase 'lastname' => 'Last name', ]; + /** + * @var TransportBuilderMock + */ + private $transportBuilderMock; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @var CustomerRepositoryInterface + */ + private $customerRepository; + + /** + * @var ExtensibleDataObjectConverter + */ + private $extensibleDataObjectConverter; + + /** + * @var CustomerFactory + */ + private $customerModelFactory; + + /** + * @var Random + */ + private $random; + + /** + * @var EncryptorInterface + */ + private $encryptor; + /** * @inheritdoc */ @@ -65,6 +109,13 @@ protected function setUp() $this->accountManagement = $this->objectManager->get(AccountManagementInterface::class); $this->customerFactory = $this->objectManager->get(CustomerInterfaceFactory::class); $this->dataObjectHelper = $this->objectManager->create(DataObjectHelper::class); + $this->transportBuilderMock = $this->objectManager->get(TransportBuilderMock::class); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); + $this->customerRepository = $this->objectManager->get(CustomerRepositoryInterface::class); + $this->extensibleDataObjectConverter = $this->objectManager->get(ExtensibleDataObjectConverter::class); + $this->customerModelFactory = $this->objectManager->get(CustomerFactory::class); + $this->random = $this->objectManager->get(Random::class); + $this->encryptor = $this->objectManager->get(EncryptorInterface::class); parent::setUp(); } @@ -82,9 +133,7 @@ public function testCreateAccountWithInvalidFields( string $errorType, array $errorMessage ): void { - $data = array_merge($this->defaultCustomerData, $customerData); - $customerEntity = $this->customerFactory->create(); - $this->dataObjectHelper->populateWithArray($customerEntity, $data, CustomerInterface::class); + $customerEntity = $this->populateCustomerEntity($this->defaultCustomerData, $customerData); $this->expectException($errorType); $this->expectExceptionMessage((string)__(...$errorMessage)); $this->accountManagement->createAccount($customerEntity, $password); @@ -156,7 +205,300 @@ public function createInvalidAccountDataProvider(): array 'The password can\'t be the same as the email address. Create a new password and try again.', ], ], + 'send_email_store_id_not_match_website' => [ + 'customer_data' => [ + CustomerInterface::WEBSITE_ID => 1, + CustomerInterface::STORE_ID => 5, + ], + 'password' => '_aPassword1', + 'error_type' => LocalizedException::class, + 'error_message' => [ + 'The store view is not in the associated website.', + ], + ], + ]; + } + + /** + * Assert that when you create customer account via admin, link with "set password" is send to customer email. + * + * @return void + */ + public function testSendEmailWithSetPasswordLink(): void + { + $customerEntity = $this->populateCustomerEntity($this->defaultCustomerData); + $newCustomerEntity = $this->accountManagement->createAccount($customerEntity); + $mailTemplate = $this->transportBuilderMock->getSentMessage()->getBody()->getParts()[0]->getRawContent(); + + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath( + sprintf("//a[contains(@href, 'customer/account/createPassword/?id=%s')]", $newCustomerEntity->getId()), + $mailTemplate + ), + 'Password creation link was not found.' + ); + } + + /** + * @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php + * @return void + */ + public function testCreateCustomerOnSecondWebsite(): void + { + $customerData = [ + CustomerInterface::WEBSITE_ID => $this->storeManager->getWebsite('test')->getId(), + CustomerInterface::STORE_ID => $this->storeManager->getStore('fixture_third_store')->getId(), + ]; + $expectedCustomerData = array_merge($this->defaultCustomerData, $customerData); + $customerEntity = $this->populateCustomerEntity($this->defaultCustomerData, $customerData); + $savedCustomerEntity = $this->accountManagement->createAccount($customerEntity); + + $this->assertNotNull($savedCustomerEntity->getId()); + $this->assertCustomerData($savedCustomerEntity, $expectedCustomerData); + } + + /** + * @return void + */ + public function testCreateNewCustomerWithPasswordHash(): void + { + $customerData = $expectedCustomerData = [ + CustomerInterface::EMAIL => 'email@example.com', + CustomerInterface::STORE_ID => 1, + CustomerInterface::FIRSTNAME => 'Tester', + CustomerInterface::LASTNAME => 'McTest', + CustomerInterface::GROUP_ID => 1, + ]; + $newCustomerEntity = $this->populateCustomerEntity($customerData); + $password = $this->random->getRandomString(8); + $passwordHash = $this->encryptor->getHash($password, true); + $savedCustomer = $this->accountManagement->createAccountWithPasswordHash( + $newCustomerEntity, + $passwordHash + ); + $this->assertNotNull($savedCustomer->getId()); + $this->assertCustomerData($savedCustomer, $expectedCustomerData); + $this->assertEmpty($savedCustomer->getSuffix()); + $this->assertEquals( + $savedCustomer->getId(), + $this->accountManagement->authenticate($customerData[CustomerInterface::EMAIL], $password)->getId() + ); + } + + /** + * Customer has two addresses one of it is allowed in website and second is not + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php + * @magentoDataFixture Magento/Store/_files/websites_different_countries.php + * @magentoConfigFixture fixture_second_store_store general/country/allow UA + * @return void + */ + public function testCreateNewCustomerWithPasswordHashWithNotAllowedCountry(): void + { + $customerId = 1; + $allowedCountryIdForSecondWebsite = 'UA'; + $store = $this->storeManager->getStore('fixture_second_store'); + $customerData = $this->customerRepository->getById($customerId); + $customerData->getAddresses()[1]->setRegion(null)->setCountryId($allowedCountryIdForSecondWebsite) + ->setRegionId(null); + $customerData->setStoreId($store->getId())->setWebsiteId($store->getWebsiteId())->setId(null); + $password = $this->random->getRandomString(8); + $passwordHash = $this->encryptor->getHash($password, true); + $savedCustomer = $this->accountManagement->createAccountWithPasswordHash( + $customerData, + $passwordHash + ); + $this->assertCount( + 1, + $savedCustomer->getAddresses(), + 'The wrong address quantity was saved' + ); + $this->assertSame( + 'UA', + $savedCustomer->getAddresses()[0]->getCountryId(), + 'The address with the disallowed country was saved' + ); + } + + /** + * @magentoAppArea frontend + * @magentoDataFixture Magento/Customer/_files/customer.php + * @return void + */ + public function testCreateNoExistingCustomer(): void + { + $existingCustId = 1; + $existingCustomer = $this->customerRepository->getById($existingCustId); + $customerData = $expectedCustomerData = [ + CustomerInterface::EMAIL => 'savecustomer@example.com', + CustomerInterface::FIRSTNAME => 'Firstsave', + CustomerInterface::LASTNAME => 'Lastsave', + CustomerInterface::ID => null, ]; + unset($expectedCustomerData[CustomerInterface::ID]); + $customerEntity = $this->populateCustomerEntity($existingCustomer->__toArray(), $customerData); + + $customerAfter = $this->accountManagement->createAccount($customerEntity, '_aPassword1'); + $this->assertGreaterThan(0, $customerAfter->getId()); + $this->assertCustomerData($customerAfter, $expectedCustomerData); + $this->accountManagement->authenticate( + $customerAfter->getEmail(), + '_aPassword1' + ); + $attributesBefore = $this->extensibleDataObjectConverter->toFlatArray( + $existingCustomer, + [], + CustomerInterface::class + ); + $attributesAfter = $this->extensibleDataObjectConverter->toFlatArray( + $customerAfter, + [], + CustomerInterface::class + ); + // ignore 'updated_at' + unset($attributesBefore['updated_at']); + unset($attributesAfter['updated_at']); + $inBeforeOnly = array_diff_assoc($attributesBefore, $attributesAfter); + $inAfterOnly = array_diff_assoc($attributesAfter, $attributesBefore); + $expectedInBefore = [ + 'email', + 'firstname', + 'id', + 'lastname', + ]; + sort($expectedInBefore); + $actualInBeforeOnly = array_keys($inBeforeOnly); + sort($actualInBeforeOnly); + $this->assertEquals($expectedInBefore, $actualInBeforeOnly); + $expectedInAfter = [ + 'created_in', + 'email', + 'firstname', + 'id', + 'lastname', + ]; + $actualInAfterOnly = array_keys($inAfterOnly); + foreach ($expectedInAfter as $item) { + $this->assertContains($item, $actualInAfterOnly); + } + } + + /** + * @return void + */ + public function testCreateCustomerInServiceVsInModel(): void + { + $password = '_aPassword1'; + $firstCustomerData = $secondCustomerData = [ + CustomerInterface::EMAIL => 'email@example.com', + CustomerInterface::FIRSTNAME => 'Tester', + CustomerInterface::LASTNAME => 'McTest', + CustomerInterface::GROUP_ID => 1, + ]; + $secondCustomerData[CustomerInterface::EMAIL] = 'email2@example.com'; + + /** @var Customer $customerModel */ + $customerModel = $this->customerModelFactory->create(); + $customerModel->setData($firstCustomerData)->setPassword($password); + $customerModel->save(); + /** @var Customer $customerModel */ + $savedModel = $this->customerModelFactory->create()->load($customerModel->getId()); + $dataInModel = $savedModel->getData(); + $newCustomerEntity = $this->populateCustomerEntity($secondCustomerData); + + $customerData = $this->accountManagement->createAccount($newCustomerEntity, $password); + $this->assertNotNull($customerData->getId()); + $savedCustomer = $this->customerRepository->getById($customerData->getId()); + + /** @var SimpleDataObjectConverter $simpleDataObjectConverter */ + $simpleDataObjectConverter = $this->objectManager->get(SimpleDataObjectConverter::class); + + $dataInService = $simpleDataObjectConverter->toFlatArray( + $savedCustomer, + CustomerInterface::class + ); + $expectedDifferences = [ + 'created_at', + 'updated_at', + 'email', + 'is_active', + 'entity_id', + 'entity_type_id', + 'password_hash', + 'attribute_set_id', + 'disable_auto_group_change', + 'confirmation', + 'reward_update_notification', + 'reward_warning_notification', + ]; + foreach ($dataInModel as $key => $value) { + if (!in_array($key, $expectedDifferences)) { + if ($value === null) { + $this->assertArrayNotHasKey($key, $dataInService); + } elseif (isset($dataInService[$key])) { + $this->assertEquals($value, $dataInService[$key], 'Failed asserting value for ' . $key); + } + } + } + $this->assertEquals($secondCustomerData[CustomerInterface::EMAIL], $dataInService['email']); + $this->assertArrayNotHasKey('is_active', $dataInService); + $this->assertArrayNotHasKey('password_hash', $dataInService); + } + + /** + * @return void + */ + public function testCreateNewCustomer(): void + { + $customerData = $expectedCustomerData = [ + CustomerInterface::EMAIL => 'email@example.com', + CustomerInterface::STORE_ID => 1, + CustomerInterface::FIRSTNAME => 'Tester', + CustomerInterface::LASTNAME => 'McTest', + CustomerInterface::GROUP_ID => 1, + ]; + $newCustomerEntity = $this->populateCustomerEntity($customerData); + + $savedCustomer = $this->accountManagement->createAccount($newCustomerEntity, '_aPassword1'); + $this->assertNotNull($savedCustomer->getId()); + $this->assertCustomerData($savedCustomer, $expectedCustomerData); + $this->assertEmpty($savedCustomer->getSuffix()); + } + + /** + * @magentoAppArea frontend + * @magentoDataFixture Magento/Customer/_files/customer.php + * @return void + */ + public function testCreateNewCustomerFromClone(): void + { + $existingCustId = 1; + $existingCustomer = $this->customerRepository->getById($existingCustId); + $customerEntity = $this->customerFactory->create(); + $this->dataObjectHelper->mergeDataObjects( + CustomerInterface::class, + $customerEntity, + $existingCustomer + ); + $customerData = $expectedCustomerData = [ + CustomerInterface::EMAIL => 'savecustomer@example.com', + CustomerInterface::FIRSTNAME => 'Firstsave', + CustomerInterface::LASTNAME => 'Lastsave', + CustomerInterface::ID => null, + ]; + unset($expectedCustomerData[CustomerInterface::ID]); + $customerEntity = $this->populateCustomerEntity($customerData, [], $customerEntity); + + $customer = $this->accountManagement->createAccount($customerEntity, '_aPassword1'); + $this->assertNotEmpty($customer->getId()); + $this->assertCustomerData($customer, $expectedCustomerData); + $this->accountManagement->authenticate( + $customer->getEmail(), + '_aPassword1', + true + ); } /** @@ -174,4 +516,52 @@ private function getRandomNumericString(int $length): string return $string; } + + /** + * Fill in customer entity using array of customer data and additional customer data. + * + * @param array $customerData + * @param array $additionalCustomerData + * @param CustomerInterface|null $customerEntity + * @return CustomerInterface + */ + private function populateCustomerEntity( + array $customerData, + array $additionalCustomerData = [], + ?CustomerInterface $customerEntity = null + ): CustomerInterface { + $customerEntity = $customerEntity ?? $this->customerFactory->create(); + $customerData = array_merge( + $customerData, + $additionalCustomerData + ); + $this->dataObjectHelper->populateWithArray( + $customerEntity, + $customerData, + CustomerInterface::class + ); + + return $customerEntity; + } + + /** + * Check that customer parameters match expected values. + * + * @param CustomerInterface $customer + * @param array $expectedData + * return void + */ + private function assertCustomerData( + CustomerInterface $customer, + array $expectedData + ): void { + $actualCustomerArray = $customer->__toArray(); + foreach ($expectedData as $key => $expectedValue) { + $this->assertEquals( + $expectedValue, + $actualCustomerArray[$key], + "Invalid expected value for $key field." + ); + } + } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/ValidateTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/ValidateTest.php new file mode 100644 index 0000000000000..8daa310d6dc03 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/ValidateTest.php @@ -0,0 +1,113 @@ +objectManager = Bootstrap::getObjectManager(); + $this->accountManagement = $this->objectManager->get(AccountManagementInterface::class); + $this->customerFactory = $this->objectManager->get(CustomerInterfaceFactory::class); + $this->dataObjectHelper = $this->objectManager->get(DataObjectHelper::class); + parent::setUp(); + } + + /** + * Validate customer fields. + * + * @dataProvider validateFieldsProvider + * + * @param array $customerData + * @param array $expectedResults + * @return void + */ + public function testValidateFields( + array $customerData, + array $expectedResults + ): void { + $customerEntity = $this->customerFactory->create(); + $this->dataObjectHelper->populateWithArray( + $customerEntity, + $customerData, + CustomerInterface::class + ); + $validationResults = $this->accountManagement->validate($customerEntity); + $this->assertEquals( + $expectedResults, + [ + 'valid' => $validationResults->isValid(), + 'messages' => $validationResults->getMessages(), + ] + ); + } + + /** + * @return array + */ + public function validateFieldsProvider(): array + { + $attributeEmptyMessage = 'The "%1" attribute value is empty. Set the attribute and try again.'; + return [ + 'without_required_fields' => [ + 'customer_data' => [], + 'expectedResults' => [ + 'valid' => false, + 'messages' => [ + (string)__($attributeEmptyMessage, 'Associate to Website'), + (string)__($attributeEmptyMessage, 'Group'), + (string)__($attributeEmptyMessage, 'First Name'), + (string)__($attributeEmptyMessage, 'Last Name'), + (string)__($attributeEmptyMessage, 'Email'), + ], + ], + ], + 'with_required_fields' => [ + 'customer_data' => [ + CustomerInterface::WEBSITE_ID => 1, + CustomerInterface::GROUP_ID => 1, + CustomerInterface::FIRSTNAME => 'Jane', + CustomerInterface::LASTNAME => 'Doe', + CustomerInterface::EMAIL => 'janedoe' . uniqid() . '@example.com', + ], + 'expectedResults' => [ + 'valid' => true, + 'messages' => [], + ], + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php index 754c949747d61..e41d7d9a441c3 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php @@ -8,13 +8,11 @@ use Magento\Customer\Api\AccountManagementInterface; use Magento\Customer\Api\AddressRepositoryInterface; -use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Customer\Api\Data\AddressInterface; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\State\ExpiredException; use Magento\Framework\Reflection\DataObjectProcessor; -use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Helper\Bootstrap; /** @@ -30,9 +28,6 @@ class AccountManagementTest extends \PHPUnit\Framework\TestCase /** @var AccountManagementInterface */ private $accountManagement; - /** @var CustomerRepositoryInterface */ - private $customerRepository; - /** @var AddressRepositoryInterface needed to setup tests */ private $addressRepository; @@ -45,18 +40,9 @@ class AccountManagementTest extends \PHPUnit\Framework\TestCase /** @var \Magento\Customer\Api\Data\AddressInterfaceFactory */ private $addressFactory; - /** @var \Magento\Customer\Api\Data\CustomerInterfaceFactory */ - private $customerFactory; - /** @var DataObjectProcessor */ private $dataProcessor; - /** @var \Magento\Framework\Api\ExtensibleDataObjectConverter */ - private $extensibleDataObjectConverter; - - /** @var StoreManagerInterface */ - private $storeManager; - /** @var \Magento\Framework\Api\DataObjectHelper */ protected $dataObjectHelper; @@ -65,16 +51,10 @@ protected function setUp() $this->objectManager = Bootstrap::getObjectManager(); $this->accountManagement = $this->objectManager ->create(\Magento\Customer\Api\AccountManagementInterface::class); - $this->customerRepository = $this->objectManager - ->create(\Magento\Customer\Api\CustomerRepositoryInterface::class); $this->addressRepository = $this->objectManager->create(\Magento\Customer\Api\AddressRepositoryInterface::class); $this->addressFactory = $this->objectManager->create(\Magento\Customer\Api\Data\AddressInterfaceFactory::class); - $this->customerFactory = $this->objectManager->create( - \Magento\Customer\Api\Data\CustomerInterfaceFactory::class - ); - $this->dataObjectHelper = $this->objectManager->create(\Magento\Framework\Api\DataObjectHelper::class); $regionFactory = $this->objectManager->create(\Magento\Customer\Api\Data\RegionInterfaceFactory::class); $address = $this->addressFactory->create(); @@ -115,12 +95,6 @@ protected function setUp() $this->dataProcessor = $this->objectManager ->create(\Magento\Framework\Reflection\DataObjectProcessor::class); - - $this->extensibleDataObjectConverter = $this->objectManager - ->create(\Magento\Framework\Api\ExtensibleDataObjectConverter::class); - - $this->storeManager = $this->objectManager - ->create(StoreManagerInterface::class); } /** @@ -620,310 +594,6 @@ public function testResendConfirmationNotNeeded() $this->accountManagement->resendConfirmation('customer@example.com', 1); } - /** - * @magentoDbIsolation enabled - */ - public function testCreateCustomerException() - { - $customerEntity = $this->customerFactory->create(); - - try { - $this->accountManagement->createAccount($customerEntity); - $this->fail('Expected exception not thrown'); - } catch (InputException $ie) { - $this->assertEquals('The customer email is missing. Enter and try again.', $ie->getMessage()); - } - } - - /** - * @magentoAppArea frontend - * @magentoDataFixture Magento/Customer/_files/customer.php - * @magentoDbIsolation enabled - */ - public function testCreateNonexistingCustomer() - { - $existingCustId = 1; - $existingCustomer = $this->customerRepository->getById($existingCustId); - - $email = 'savecustomer@example.com'; - $firstName = 'Firstsave'; - $lastName = 'Lastsave'; - $customerData = array_merge( - $existingCustomer->__toArray(), - [ - 'email' => $email, - 'firstname' => $firstName, - 'lastname' => $lastName, - 'id' => null - ] - ); - $customerEntity = $this->customerFactory->create(); - $this->dataObjectHelper->populateWithArray( - $customerEntity, - $customerData, - \Magento\Customer\Api\Data\CustomerInterface::class - ); - - $customerAfter = $this->accountManagement->createAccount($customerEntity, '_aPassword1'); - $this->assertGreaterThan(0, $customerAfter->getId()); - $this->assertEquals($email, $customerAfter->getEmail()); - $this->assertEquals($firstName, $customerAfter->getFirstname()); - $this->assertEquals($lastName, $customerAfter->getLastname()); - $this->accountManagement->authenticate( - $customerAfter->getEmail(), - '_aPassword1' - ); - $attributesBefore = $this->extensibleDataObjectConverter->toFlatArray( - $existingCustomer, - [], - \Magento\Customer\Api\Data\CustomerInterface::class - ); - $attributesAfter = $this->extensibleDataObjectConverter->toFlatArray( - $customerAfter, - [], - \Magento\Customer\Api\Data\CustomerInterface::class - ); - // ignore 'updated_at' - unset($attributesBefore['updated_at']); - unset($attributesAfter['updated_at']); - $inBeforeOnly = array_diff_assoc($attributesBefore, $attributesAfter); - $inAfterOnly = array_diff_assoc($attributesAfter, $attributesBefore); - $expectedInBefore = [ - 'email', - 'firstname', - 'id', - 'lastname', - ]; - sort($expectedInBefore); - $actualInBeforeOnly = array_keys($inBeforeOnly); - sort($actualInBeforeOnly); - $this->assertEquals($expectedInBefore, $actualInBeforeOnly); - $expectedInAfter = [ - 'created_in', - 'email', - 'firstname', - 'id', - 'lastname', - ]; - $actualInAfterOnly = array_keys($inAfterOnly); - foreach ($expectedInAfter as $item) { - $this->assertContains($item, $actualInAfterOnly); - } - } - - /** - * @magentoDbIsolation enabled - */ - public function testCreateCustomerInServiceVsInModel() - { - $email = 'email@example.com'; - $email2 = 'email2@example.com'; - $firstname = 'Tester'; - $lastname = 'McTest'; - $groupId = 1; - $password = '_aPassword1'; - - /** @var \Magento\Customer\Model\Customer $customerModel */ - $customerModel = $this->objectManager->create(\Magento\Customer\Model\CustomerFactory::class)->create(); - $customerModel->setEmail($email) - ->setFirstname($firstname) - ->setLastname($lastname) - ->setGroupId($groupId) - ->setPassword($password); - $customerModel->save(); - /** @var \Magento\Customer\Model\Customer $customerModel */ - $savedModel = $this->objectManager - ->create(\Magento\Customer\Model\CustomerFactory::class) - ->create() - ->load($customerModel->getId()); - $dataInModel = $savedModel->getData(); - - $newCustomerEntity = $this->customerFactory->create() - ->setEmail($email2) - ->setFirstname($firstname) - ->setLastname($lastname) - ->setGroupId($groupId); - $customerData = $this->accountManagement->createAccount($newCustomerEntity, $password); - $this->assertNotNull($customerData->getId()); - $savedCustomer = $this->customerRepository->getById($customerData->getId()); - - /** @var \Magento\Framework\Api\SimpleDataObjectConverter $simpleDataObjectConverter */ - $simpleDataObjectConverter = Bootstrap::getObjectManager() - ->get(\Magento\Framework\Api\SimpleDataObjectConverter::class); - - $dataInService = $simpleDataObjectConverter->toFlatArray( - $savedCustomer, - \Magento\Customer\Api\Data\CustomerInterface::class - ); - $expectedDifferences = [ - 'created_at', - 'updated_at', - 'email', - 'is_active', - 'entity_id', - 'entity_type_id', - 'password_hash', - 'attribute_set_id', - 'disable_auto_group_change', - 'confirmation', - 'reward_update_notification', - 'reward_warning_notification', - ]; - foreach ($dataInModel as $key => $value) { - if (!in_array($key, $expectedDifferences)) { - if ($value === null) { - $this->assertArrayNotHasKey($key, $dataInService); - } else { - if (isset($dataInService[$key])) { - $this->assertEquals($value, $dataInService[$key], 'Failed asserting value for ' . $key); - } - } - } - } - $this->assertEquals($email2, $dataInService['email']); - $this->assertArrayNotHasKey('is_active', $dataInService); - $this->assertArrayNotHasKey('password_hash', $dataInService); - } - - /** - * @magentoDbIsolation enabled - */ - public function testCreateNewCustomer() - { - $email = 'email@example.com'; - $storeId = 1; - $firstname = 'Tester'; - $lastname = 'McTest'; - $groupId = 1; - - $newCustomerEntity = $this->customerFactory->create() - ->setStoreId($storeId) - ->setEmail($email) - ->setFirstname($firstname) - ->setLastname($lastname) - ->setGroupId($groupId); - $savedCustomer = $this->accountManagement->createAccount($newCustomerEntity, '_aPassword1'); - $this->assertNotNull($savedCustomer->getId()); - $this->assertEquals($email, $savedCustomer->getEmail()); - $this->assertEquals($storeId, $savedCustomer->getStoreId()); - $this->assertEquals($firstname, $savedCustomer->getFirstname()); - $this->assertEquals($lastname, $savedCustomer->getLastname()); - $this->assertEquals($groupId, $savedCustomer->getGroupId()); - $this->assertTrue(!$savedCustomer->getSuffix()); - } - - /** - * @magentoDbIsolation enabled - */ - public function testCreateNewCustomerWithPasswordHash() - { - $email = 'email@example.com'; - $storeId = 1; - $firstname = 'Tester'; - $lastname = 'McTest'; - $groupId = 1; - - $newCustomerEntity = $this->customerFactory->create() - ->setStoreId($storeId) - ->setEmail($email) - ->setFirstname($firstname) - ->setLastname($lastname) - ->setGroupId($groupId); - /** @var \Magento\Framework\Math\Random $mathRandom */ - $password = $this->objectManager->get(\Magento\Framework\Math\Random::class)->getRandomString(8); - /** @var \Magento\Framework\Encryption\EncryptorInterface $encryptor */ - $encryptor = $this->objectManager->get(\Magento\Framework\Encryption\EncryptorInterface::class); - $passwordHash = $encryptor->getHash($password, true); - $savedCustomer = $this->accountManagement->createAccountWithPasswordHash( - $newCustomerEntity, - $passwordHash - ); - $this->assertNotNull($savedCustomer->getId()); - $this->assertEquals($email, $savedCustomer->getEmail()); - $this->assertEquals($storeId, $savedCustomer->getStoreId()); - $this->assertEquals($firstname, $savedCustomer->getFirstname()); - $this->assertEquals($lastname, $savedCustomer->getLastname()); - $this->assertEquals($groupId, $savedCustomer->getGroupId()); - $this->assertTrue(!$savedCustomer->getSuffix()); - $this->assertEquals( - $savedCustomer->getId(), - $this->accountManagement->authenticate($email, $password)->getId() - ); - } - - /** - * Customer has two addresses one of it is allowed in website and second is not - * - * @magentoDataFixture Magento/Customer/_files/customer.php - * @magentoDataFixture Magento/Customer/_files/customer_two_addresses.php - * @magentoDataFixture Magento/Store/_files/websites_different_countries.php - * @magentoConfigFixture fixture_second_store_store general/country/allow UA - * @return void - */ - public function testCreateNewCustomerWithPasswordHashWithNotAllowedCountry() - { - $customerId = 1; - $allowedCountryIdForSecondWebsite = 'UA'; - $store = $this->storeManager->getStore('fixture_second_store'); - $customerData = $this->customerRepository->getById($customerId); - $customerData->getAddresses()[1]->setRegion(null)->setCountryId($allowedCountryIdForSecondWebsite) - ->setRegionId(null); - $customerData->setStoreId($store->getId())->setWebsiteId($store->getWebsiteId())->setId(null); - $encryptor = $this->objectManager->get(\Magento\Framework\Encryption\EncryptorInterface::class); - /** @var \Magento\Framework\Math\Random $mathRandom */ - $password = $this->objectManager->get(\Magento\Framework\Math\Random::class)->getRandomString(8); - $passwordHash = $encryptor->getHash($password, true); - $savedCustomer = $this->accountManagement->createAccountWithPasswordHash( - $customerData, - $passwordHash - ); - $this->assertCount( - 1, - $savedCustomer->getAddresses(), - 'The wrong address quantity was saved' - ); - $this->assertSame( - 'UA', - $savedCustomer->getAddresses()[0]->getCountryId(), - 'The address with the disallowed country was saved' - ); - } - - /** - * @magentoAppArea frontend - * @magentoDataFixture Magento/Customer/_files/customer.php - */ - public function testCreateNewCustomerFromClone() - { - $email = 'savecustomer@example.com'; - $firstName = 'Firstsave'; - $lastname = 'Lastsave'; - - $existingCustId = 1; - $existingCustomer = $this->customerRepository->getById($existingCustId); - $customerEntity = $this->customerFactory->create(); - $this->dataObjectHelper->mergeDataObjects( - \Magento\Customer\Api\Data\CustomerInterface::class, - $customerEntity, - $existingCustomer - ); - $customerEntity->setEmail($email) - ->setFirstname($firstName) - ->setLastname($lastname) - ->setId(null); - - $customer = $this->accountManagement->createAccount($customerEntity, '_aPassword1'); - $this->assertNotEmpty($customer->getId()); - $this->assertEquals($email, $customer->getEmail()); - $this->assertEquals($firstName, $customer->getFirstname()); - $this->assertEquals($lastname, $customer->getLastname()); - $this->accountManagement->authenticate( - $customer->getEmail(), - '_aPassword1', - true - ); - } - /** * @magentoDataFixture Magento/Customer/_files/customer.php */ From eac1a534568c49b3eaee622d183ac7cddb1f0ae5 Mon Sep 17 00:00:00 2001 From: Roman Zhupanyn Date: Fri, 6 Mar 2020 14:15:10 +0200 Subject: [PATCH 2/8] MC-32130: Admin: Reset customer password on edit customer page in admin --- .../AccountManagement/ResetPasswordTest.php | 147 ++++++++++++++++++ .../Customer/Model/AccountManagementTest.php | 67 -------- 2 files changed, 147 insertions(+), 67 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/ResetPasswordTest.php diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/ResetPasswordTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/ResetPasswordTest.php new file mode 100644 index 0000000000000..012838ebdf697 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/ResetPasswordTest.php @@ -0,0 +1,147 @@ +objectManager = Bootstrap::getObjectManager(); + $this->accountManagement = $this->objectManager->get(AccountManagementInterface::class); + $this->transportBuilderMock = $this->objectManager->get(TransportBuilderMock::class); + $this->customerRegistry = $this->objectManager->get(CustomerRegistry::class); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); + parent::setUp(); + } + + /** + * Assert that when you reset customer password via admin, link with "Set a New Password" is send to customer email. + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * @return void + */ + public function testSendEmailWithSetNewPasswordLink(): void + { + $this->accountManagement->initiatePasswordReset( + 'customer@example.com', + AccountManagement::EMAIL_REMINDER, + 1 + ); + $customerSecure = $this->customerRegistry->retrieveSecureData(1); + $mailTemplate = $this->transportBuilderMock->getSentMessage()->getBody()->getParts()[0]->getRawContent(); + + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath( + sprintf( + '//a[contains(@href, \'customer/account/createPassword/?id=%1$d&token=%2$s\')]', + $customerSecure->getId(), + $customerSecure->getRpToken() + ), + $mailTemplate + ), + 'Reset password creation link was not found.' + ); + } + + /** + * @magentoAppArea frontend + * @magentoDataFixture Magento/Customer/_files/customer.php + * @return void + */ + public function testSendPasswordResetLink(): void + { + $email = 'customer@example.com'; + $websiteId = (int)$this->storeManager->getWebsite('base')->getId(); + + $this->accountManagement->initiatePasswordReset($email, AccountManagement::EMAIL_RESET, $websiteId); + } + + /** + * @magentoAppArea frontend + * @magentoDataFixture Magento/Customer/_files/customer.php + * @return void + */ + public function testSendPasswordResetLinkDefaultWebsite(): void + { + $email = 'customer@example.com'; + + $this->accountManagement->initiatePasswordReset($email, AccountManagement::EMAIL_RESET); + } + + /** + * @magentoAppArea frontend + * @dataProvider passwordResetErrorsProvider + * @magentoDataFixture Magento/Customer/_files/customer.php + * @param string $email + * @param int|null $websiteId + * @return void + */ + public function testPasswordResetErrors(string $email, ?int $websiteId = null): void + { + $websiteId = $websiteId ?? (int)$this->storeManager->getWebsite('base')->getId(); + $this->expectExceptionObject( + NoSuchEntityException::doubleField('email', $email, 'websiteId', $websiteId) + ); + $this->accountManagement->initiatePasswordReset( + $email, + AccountManagement::EMAIL_RESET, + $websiteId + ); + } + + /** + * @return array + */ + public function passwordResetErrorsProvider(): array + { + return [ + 'wrong_email' => [ + 'email' => 'foo@example.com', + ], + 'wrong_website_id' => [ + 'email' => 'customer@example.com', + 'website_id' => 0, + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php index 754c949747d61..9d78a6827f7ad 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php @@ -387,73 +387,6 @@ public function testValidateResetPasswordLinkTokenAmbiguous() $this->accountManagement->validateResetPasswordLinkToken(null, $token); } - /** - * @magentoAppArea frontend - * @magentoDataFixture Magento/Customer/_files/customer.php - */ - public function testSendPasswordResetLink() - { - $email = 'customer@example.com'; - - $this->accountManagement->initiatePasswordReset($email, AccountManagement::EMAIL_RESET, 1); - } - - /** - * @magentoAppArea frontend - * @magentoDataFixture Magento/Customer/_files/customer.php - */ - public function testSendPasswordResetLinkDefaultWebsite() - { - $email = 'customer@example.com'; - - $this->accountManagement->initiatePasswordReset($email, AccountManagement::EMAIL_RESET); - } - - /** - * @magentoDataFixture Magento/Customer/_files/customer.php - * - */ - public function testSendPasswordResetLinkBadEmailOrWebsite() - { - $email = 'foo@example.com'; - - try { - $this->accountManagement->initiatePasswordReset( - $email, - AccountManagement::EMAIL_RESET, - 0 - ); - $this->fail('Expected exception not thrown.'); - } catch (NoSuchEntityException $e) { - $expectedParams = [ - 'fieldName' => 'email', - 'fieldValue' => $email, - 'field2Name' => 'websiteId', - 'field2Value' => 0, - ]; - $this->assertEquals($expectedParams, $e->getParameters()); - } - } - - /** - * @magentoDataFixture Magento/Customer/_files/customer.php - */ - public function testSendPasswordResetLinkBadEmailDefaultWebsite() - { - $email = 'foo@example.com'; - - try { - $this->accountManagement->initiatePasswordReset( - $email, - AccountManagement::EMAIL_RESET - ); - $this->fail('Expected exception not thrown.'); - } catch (NoSuchEntityException $nsee) { - // App area is frontend, so we expect websiteId of 1. - $this->assertEquals('No such entity with email = foo@example.com, websiteId = 1', $nsee->getMessage()); - } - } - /** * @magentoDataFixture Magento/Customer/_files/customer.php */ From c1c1dfee2ef9928010195473b4a72e1bf3299756 Mon Sep 17 00:00:00 2001 From: Roman Zhupanyn Date: Fri, 6 Mar 2020 16:33:38 +0200 Subject: [PATCH 3/8] MC-32126: Admin: Create/update/delete customer --- .../Controller/Adminhtml/Index/SaveTest.php | 18 +++++++++--------- .../Controller/Adminhtml/IndexTest.php | 19 +++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/SaveTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/SaveTest.php index aed6003ea76ac..f532e2fcb7182 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/SaveTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/SaveTest.php @@ -36,7 +36,7 @@ class SaveTest extends AbstractBackendController * * @var string */ - private $_baseControllerUrl = 'http://localhost/index.php/backend/customer/index/'; + private $baseControllerUrl = 'backend/customer/index/'; /** @var CustomerRepositoryInterface */ private $customerRepository; @@ -83,7 +83,7 @@ public function testCreateCustomer(array $postData, array $expectedData): void $this->equalTo([(string)__('You saved the customer.')]), MessageInterface::TYPE_SUCCESS ); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'index/key/')); + $this->assertRedirect($this->stringContains($this->baseControllerUrl . 'index/key/')); $this->assertCustomerData( $postData['customer'][CustomerData::EMAIL], (int)$postData['customer'][CustomerData::WEBSITE_ID], @@ -158,7 +158,7 @@ public function testCreateCustomerErrors(array $postData, array $expectedData, a ); $this->assertNotEmpty($this->session->getCustomerFormData()); $this->assertArraySubset($expectedData, $this->session->getCustomerFormData()); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'new/key/')); + $this->assertRedirect($this->stringContains($this->baseControllerUrl . 'new/key/')); } /** @@ -251,8 +251,8 @@ public function testUpdateCustomer(): void $this->equalTo([(string)__('You saved the customer.')]), MessageInterface::TYPE_SUCCESS ); - $this->assertRedirect($this->stringStartsWith( - $this->_baseControllerUrl . 'edit/id/' . $customerData->getId() + $this->assertRedirect($this->stringContains( + $this->baseControllerUrl . 'edit/id/' . $customerData->getId() )); $this->assertCustomerData($customerData->getEmail(), (int)$customerData->getWebsiteId(), $expectedData); $this->assertCustomerSubscription( @@ -289,7 +289,7 @@ public function testExistingCustomerUnsubscribeNewsletter(): void $this->equalTo([(string)__('You saved the customer.')]), MessageInterface::TYPE_SUCCESS ); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'index/key/')); + $this->assertRedirect($this->stringContains($this->baseControllerUrl . 'index/key/')); $this->assertCustomerSubscription( (int)$customerData->getId(), (int)$customerData->getWebsiteId(), @@ -344,7 +344,7 @@ public function testExistingCustomerChangeEmail(): void * Check that no errors were generated and set to session */ $this->assertSessionMessages($this->isEmpty(), MessageInterface::TYPE_ERROR); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'index/key/')); + $this->assertRedirect($this->stringContains($this->baseControllerUrl . 'index/key/')); } /** @@ -384,7 +384,7 @@ public function testCreateSameEmailFormatDateError(): void true, 'Customer form data should be formatted' ); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'new/key/')); + $this->assertRedirect($this->stringContains($this->baseControllerUrl . 'new/key/')); } /** @@ -449,7 +449,7 @@ private function dispatchCustomerSave(array $postData, array $params = []): void if (!empty($params)) { $this->getRequest()->setParams($params); } - $this->dispatch('backend/customer/index/save'); + $this->dispatch($this->baseControllerUrl . 'save'); } /** diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php index 756270344d720..23ea8011e9bc9 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php @@ -7,8 +7,8 @@ namespace Magento\Customer\Controller\Adminhtml; use Magento\Backend\Model\Session; +use Magento\Customer\Api\CustomerNameGenerationInterface; use Magento\Customer\Api\CustomerRepositoryInterface; -use Magento\Customer\Helper\View; use Magento\Customer\Model\EmailNotification; use Magento\TestFramework\Helper\Bootstrap; use Magento\Framework\App\Request\Http as HttpRequest; @@ -25,13 +25,13 @@ class IndexTest extends AbstractBackendController * * @var string */ - protected $_baseControllerUrl; + private $baseControllerUrl = 'backend/customer/index/'; /** @var CustomerRepositoryInterface */ - protected $customerRepository; + private $customerRepository; - /** @var View */ - protected $customerViewHelper; + /** @var CustomerNameGenerationInterface */ + private $customerViewHelper; /** * @inheritDoc @@ -39,9 +39,8 @@ class IndexTest extends AbstractBackendController protected function setUp() { parent::setUp(); - $this->_baseControllerUrl = 'http://localhost/index.php/backend/customer/index/'; $this->customerRepository = $this->_objectManager->get(CustomerRepositoryInterface::class); - $this->customerViewHelper = $this->_objectManager->get(View::class); + $this->customerViewHelper = $this->_objectManager->get(CustomerNameGenerationInterface::class); } /** @@ -173,7 +172,7 @@ public function testResetPasswordActionNoCustomerId() // No customer ID in post, will just get redirected to base $this->getRequest()->setMethod(HttpRequest::METHOD_GET); $this->dispatch('backend/customer/index/resetPassword'); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl)); + $this->assertRedirect($this->stringContains($this->baseControllerUrl)); } /** @@ -185,7 +184,7 @@ public function testResetPasswordActionBadCustomerId() $this->getRequest()->setMethod(HttpRequest::METHOD_GET); $this->getRequest()->setPostValue(['customer_id' => '789']); $this->dispatch('backend/customer/index/resetPassword'); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl)); + $this->assertRedirect($this->stringContains($this->baseControllerUrl)); } /** @@ -200,7 +199,7 @@ public function testResetPasswordActionSuccess() $this->equalTo(['The customer will receive an email with a link to reset password.']), \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS ); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'edit')); + $this->assertRedirect($this->stringContains($this->baseControllerUrl . 'edit')); } /** From ebb1fae1439e178463092c38a2448a74942b9e3c Mon Sep 17 00:00:00 2001 From: DmytroPaidych Date: Mon, 16 Mar 2020 10:17:26 +0200 Subject: [PATCH 4/8] MC-32128: Admin: create shipment for order --- ...th_two_order_items_with_simple_product.php | 88 +++++ ...der_items_with_simple_product_rollback.php | 36 ++ .../Save/CreateShipmentForOrderTest.php | 334 ++++++++++++++++++ 3 files changed, 458 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_two_order_items_with_simple_product.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_two_order_items_with_simple_product_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save/CreateShipmentForOrderTest.php diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_two_order_items_with_simple_product.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_two_order_items_with_simple_product.php new file mode 100644 index 0000000000000..48f5d5dd99f80 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_two_order_items_with_simple_product.php @@ -0,0 +1,88 @@ +get(OrderAddressInterfaceFactory::class); +/** @var OrderPaymentInterfaceFactory $paymentFactory */ +$paymentFactory = $objectManager->get(OrderPaymentInterfaceFactory::class); +/** @var OrderInterfaceFactory $orderFactory */ +$orderFactory = $objectManager->get(OrderInterfaceFactory::class); +/** @var OrderItemInterfaceFactory $orderItemFactory */ +$orderItemFactory = $objectManager->get(OrderItemInterfaceFactory::class); +/** @var StoreManagerInterface $storeManager */ +$storeManager = $objectManager->get(StoreManagerInterface::class); +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); + +$billingAddress = $addressFactory->create(['data' => $addressData]); +$billingAddress->setAddressType(Address::TYPE_BILLING); +$shippingAddress = $addressFactory->create(['data' => $addressData]); +$shippingAddress->setAddressType(Address::TYPE_SHIPPING); +$payment = $paymentFactory->create(); +$payment->setMethod('checkmo')->setAdditionalInformation( + [ + 'last_trans_id' => '11122', + 'metadata' => [ + 'type' => 'free', + 'fraudulent' => false, + ] + ] +); + +$defaultStoreId = $storeManager->getStore('default')->getId(); +$order = $orderFactory->create(); +$order->setIncrementId('100000001') + ->setState(Order::STATE_PROCESSING) + ->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_PROCESSING)) + ->setSubtotal(20) + ->setGrandTotal(20) + ->setBaseSubtotal(20) + ->setBaseGrandTotal(20) + ->setCustomerIsGuest(false) + ->setCustomerId($customer->getId()) + ->setCustomerEmail($customer->getEmail()) + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->setStoreId($defaultStoreId) + ->setPayment($payment); + +$orderItem = $orderItemFactory->create(); +$orderItem->setProductId($product->getId()) + ->setQtyOrdered(5) + ->setBasePrice($product->getPrice()) + ->setPrice($product->getPrice()) + ->setRowTotal($product->getPrice()) + ->setProductType($product->getTypeId()) + ->setName($product->getName()) + ->setSku($product->getSku()); +$order->addItem($orderItem); + +$orderItem = $orderItemFactory->create(); +$orderItem->setProductId($customDesignProduct->getId()) + ->setQtyOrdered(5) + ->setBasePrice($customDesignProduct->getPrice()) + ->setPrice($customDesignProduct->getPrice()) + ->setRowTotal($customDesignProduct->getPrice()) + ->setProductType($customDesignProduct->getTypeId()) + ->setName($customDesignProduct->getName()) + ->setSku($customDesignProduct->getSku()); +$order->addItem($orderItem); +$orderRepository->save($order); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_two_order_items_with_simple_product_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_two_order_items_with_simple_product_rollback.php new file mode 100644 index 0000000000000..b76b5178d3d25 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_two_order_items_with_simple_product_rollback.php @@ -0,0 +1,36 @@ +get(Registry::class); +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +/** @var CollectionFactory $orderCollectionFactory */ +$orderCollectionFactory = $objectManager->get(CollectionFactory::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +$order = $orderCollectionFactory->create() + ->addFieldToFilter(OrderInterface::INCREMENT_ID, '100000001') + ->setPageSize(1) + ->getFirstItem(); +if ($order->getId()) { + $orderRepository->delete($order); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +require __DIR__ . '/../../../Magento/Customer/_files/customer_rollback.php'; +require __DIR__ . '/../../../Magento/Catalog/_files/products_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save/CreateShipmentForOrderTest.php b/dev/tests/integration/testsuite/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save/CreateShipmentForOrderTest.php new file mode 100644 index 0000000000000..20543f808c316 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Shipping/Controller/Adminhtml/Order/Shipment/Save/CreateShipmentForOrderTest.php @@ -0,0 +1,334 @@ +escaper = $this->_objectManager->get(Escaper::class); + } + + /** + * Assert that shipment created successfully. + * + * @magentoDataFixture Magento/Sales/_files/order_with_two_order_items_with_simple_product.php + * @dataProvider dataForCreateShipmentDataProvider + * + * @param array $dataForBuildPostData + * @param array $expectedShippedQtyBySku + * @return void + */ + public function testCreateOrderShipment(array $dataForBuildPostData, array $expectedShippedQtyBySku): void + { + $postData = $this->createPostData($dataForBuildPostData); + $order = $this->orderRepository->get($postData['order_id']); + $shipment = $this->getShipment($order); + $this->assertNull($shipment->getEntityId()); + $this->performShipmentCreationRequest($postData); + $this->assertCreateShipmentRequestSuccessfullyPerformed((int)$order->getEntityId()); + $createdShipment = $this->getShipment($order); + $this->assertNotNull($createdShipment->getEntityId()); + $shipmentItems = $createdShipment->getItems(); + $this->assertCount(count($expectedShippedQtyBySku), $shipmentItems); + foreach ($shipmentItems as $shipmentItem) { + $this->assertEquals($expectedShippedQtyBySku[$shipmentItem->getSku()], $shipmentItem->getQty()); + } + } + + /** + * Data for create full or partial order shipment POST data. + * + * @return array + */ + public function dataForCreateShipmentDataProvider(): array + { + return [ + 'create_full_shipment' => [ + [ + 'order_increment_id' => '100000001', + 'items_count_to_ship_by_sku' => [ + 'simple' => 5, + 'custom-design-simple-product' => 5, + ], + 'comment_text' => 'Create full shipment', + ], + [ + 'simple' => 5, + 'custom-design-simple-product' => 5, + ], + ], + 'create_partial_shipment' => [ + [ + 'order_increment_id' => '100000001', + 'items_count_to_ship_by_sku' => [ + 'simple' => 3, + 'custom-design-simple-product' => 2, + ], + 'comment_text' => 'Create partial shipment', + ], + [ + 'simple' => 3, + 'custom-design-simple-product' => 2, + ], + ], + 'create_shipment_for_one_of_product' => [ + [ + 'order_increment_id' => '100000001', + 'items_count_to_ship_by_sku' => [ + 'simple' => 4, + 'custom-design-simple-product' => 0, + ], + 'comment_text' => 'Create partial shipment', + ], + [ + 'simple' => 4, + ], + ], + 'create_shipment_qty_more_that_ordered' => [ + [ + 'order_increment_id' => '100000001', + 'items_count_to_ship_by_sku' => [ + 'simple' => 150, + 'custom-design-simple-product' => 5, + ], + 'comment_text' => 'Create partial shipment', + ], + [ + 'simple' => 5, + 'custom-design-simple-product' => 5, + ], + ], + 'create_shipment_qty_less_that_zero' => [ + [ + 'order_increment_id' => '100000001', + 'items_count_to_ship_by_sku' => [ + 'simple' => -10, + 'custom-design-simple-product' => 5, + ], + 'comment_text' => 'Create partial shipment', + ], + [ + 'custom-design-simple-product' => 5, + ], + ], + 'create_shipment_without_counts' => [ + [ + 'order_increment_id' => '100000001', + 'items_count_to_ship_by_sku' => [], + 'comment_text' => 'Create partial shipment', + ], + [ + 'simple' => 5, + 'custom-design-simple-product' => 5, + ], + ], + ]; + } + + /** + * Assert that body contains 404 error and forwarded to no-route if + * requested POST data is empty. + * + * @magentoDataFixture Magento/Sales/_files/order_with_customer.php + * + * @return void + */ + public function testCreateOrderShipmentWithoutPostData(): void + { + $this->performShipmentCreationRequest([]); + $this->assert404NotFound(); + } + + /** + * Assert that if we doesn't send order_id it will forwarded to no-rout and contains error 404. + * + * @magentoDataFixture Magento/Sales/_files/order_with_customer.php + * + * @return void + */ + public function testCreateOrderShipmentWithoutOrderId(): void + { + $dataToSend = [ + 'order_increment_id' => '100000001', + 'items_count_to_ship_by_sku' => [ + 'simple' => 2, + ], + 'comment_text' => 'Create full shipment', + ]; + $postData = $this->createPostData($dataToSend); + unset($postData['order_id']); + $this->performShipmentCreationRequest($postData); + $this->assert404NotFound(); + } + + /** + * Assert that if we send POST data with wrong order item ids we got error message. + * + * @magentoDataFixture Magento/Sales/_files/order_with_customer.php + * + * @return void + */ + public function testCreateOrderShipmentWithWrongItemsIds(): void + { + $orderId = $this->getOrder('100000001')->getEntityId(); + $postData = [ + 'order_id' => $orderId, + 'shipment' => + [ + 'items' => [ + 678678 => 4 + ], + ], + ]; + $this->performShipmentCreationRequest($postData); + $this->assertCreateShipmentRequestWithError( + "Shipment Document Validation Error(s):\nYou can't create a shipment without products.", + "admin/order_shipment/new/order_id/{$orderId}" + ); + } + + /** + * Assert that if we send POST data with alphabet order item count we got error message. + * + * @magentoDataFixture Magento/Sales/_files/order_with_customer.php + * + * @return void + */ + public function testCreateOrderShipmentWithAlphabetQty(): void + { + $dataToSend = [ + 'order_increment_id' => '100000001', + 'items_count_to_ship_by_sku' => [ + 'simple' => 'test_letters', + ], + 'comment_text' => 'Create full shipment', + ]; + $postData = $this->createPostData($dataToSend); + $this->performShipmentCreationRequest($postData); + $this->assertCreateShipmentRequestWithError( + "Shipment Document Validation Error(s):\nYou can't create a shipment without products.", + "admin/order_shipment/new/order_id/{$postData['order_id']}" + ); + } + + /** + * @inheritdoc + */ + public function assert404NotFound() + { + $this->assertEquals('noroute', $this->getRequest()->getControllerName()); + $this->assertContains('404 Error', $this->getResponse()->getBody()); + $this->assertContains('Page not found', $this->getResponse()->getBody()); + } + + /** + * Set POST data and type POST to request + * and perform request by path backend/admin/order_shipment/save. + * + * @param array $postData + * @return void + */ + private function performShipmentCreationRequest(array $postData): void + { + $this->getRequest()->setPostValue($postData) + ->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('backend/admin/order_shipment/save'); + } + + /** + * Assert that after create shipment session message manager + * contain message "The shipment has been created." and redirect to sales/order/view is created. + * + * @param int $orderId + * @return void + */ + private function assertCreateShipmentRequestSuccessfullyPerformed(int $orderId): void + { + $this->assertSessionMessages( + $this->equalTo([(string)__('The shipment has been created.')]), + MessageInterface::TYPE_SUCCESS + ); + $this->assertRedirect($this->stringContains('sales/order/view/order_id/' . $orderId)); + } + + /** + * Assert that session message manager contain provided error message and + * redirect created if it was provided. + * + * @param string $message + * @param string|null $redirect + * @param bool $isNeedEscapeMessage + * @return void + */ + private function assertCreateShipmentRequestWithError( + string $message, + ?string $redirect = null, + bool $isNeedEscapeMessage = true + ): void { + $assertMessage = $isNeedEscapeMessage + ? $this->escaper->escapeHtml((string)__($message)) : (string)__($message); + $this->assertSessionMessages( + $this->equalTo([$assertMessage]), + MessageInterface::TYPE_ERROR + ); + $this->assertRedirect($this->stringContains($redirect)); + } + + /** + * Create POST data for create shipment for order. + * + * @param array $dataForBuildPostData + * @return array + */ + private function createPostData(array $dataForBuildPostData): array + { + $result = []; + $order = $this->getOrder($dataForBuildPostData['order_increment_id']); + $result['order_id'] = (int)$order->getEntityId(); + $shipment = []; + $shipment['items'] = []; + foreach ($order->getItems() as $orderItem) { + if (!isset($dataForBuildPostData['items_count_to_ship_by_sku'][$orderItem->getSku()])) { + continue; + } + $shipment['items'][$orderItem->getItemId()] + = $dataForBuildPostData['items_count_to_ship_by_sku'][$orderItem->getSku()]; + } + if (empty($shipment['items'])) { + unset($shipment['items']); + } + + $shipment['comment_text'] = $dataForBuildPostData['comment_text']; + $result['shipment'] = $shipment; + + return $result; + } +} From 5932b5904fe7460ad687c96107399089219a3df6 Mon Sep 17 00:00:00 2001 From: DmytroPaidych Date: Mon, 16 Mar 2020 12:24:06 +0200 Subject: [PATCH 5/8] MC-32134: Storefront: Customer wish list on customer profile --- .../Model/GetWishlistByCustomerId.php | 61 +++++ .../Wishlist/Block/Customer/SharingTest.php | 61 +++++ .../Customer/Wishlist/Item/ColumnTest.php | 124 +++++++-- .../Wishlist/Block/Customer/WishlistTest.php | 39 ++- .../Wishlist/Controller/Index/AddTest.php | 189 ++++++++++++++ .../Wishlist/Controller/Index/AllcartTest.php | 110 ++++++++ .../Wishlist/Controller/Index/CartTest.php | 120 +++++++++ .../Wishlist/Controller/Index/IndexTest.php | 82 ++++++ .../Wishlist/Controller/Index/PluginTest.php | 45 +++- .../Wishlist/Controller/Index/RemoveTest.php | 79 ++++++ .../Wishlist/Controller/Index/SendTest.php | 180 +++++++++++++ .../Index/UpdateItemOptionsTest.php | 198 ++++++++++++++ .../Wishlist/Controller/Index/UpdateTest.php | 98 +++++++ .../Magento/Wishlist/Controller/IndexTest.php | 190 -------------- .../Magento/Wishlist/Model/ItemTest.php | 168 +++++++++--- .../Magento/Wishlist/Model/WishlistTest.php | 246 ++++++++++++++---- .../_files/wishlist_shared_rollback.php | 9 + .../wishlist_with_configurable_product.php | 17 ++ ...ist_with_configurable_product_rollback.php | 10 + .../_files/wishlist_with_simple_product.php | 16 ++ .../wishlist_with_simple_product_rollback.php | 9 + 21 files changed, 1735 insertions(+), 316 deletions(-) create mode 100644 dev/tests/integration/framework/Magento/TestFramework/Wishlist/Model/GetWishlistByCustomerId.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/SharingTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/AddTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/AllcartTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/CartTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/IndexTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/RemoveTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/SendTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/UpdateItemOptionsTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/UpdateTest.php delete mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/Controller/IndexTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_shared_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_with_configurable_product.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_with_configurable_product_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_with_simple_product.php create mode 100644 dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_with_simple_product_rollback.php diff --git a/dev/tests/integration/framework/Magento/TestFramework/Wishlist/Model/GetWishlistByCustomerId.php b/dev/tests/integration/framework/Magento/TestFramework/Wishlist/Model/GetWishlistByCustomerId.php new file mode 100644 index 0000000000000..93f170466cb40 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Wishlist/Model/GetWishlistByCustomerId.php @@ -0,0 +1,61 @@ +wishlistFactory = $wishlistFactory; + } + + /** + * Load wish list by customer id. + * + * @param int $customerId + * @return Wishlist + */ + public function execute(int $customerId): Wishlist + { + return $this->wishlistFactory->create()->loadByCustomerId($customerId, true); + } + + /** + * Get wish list item by sku. + * + * @param int $customerId + * @param string $sku + * @return null|Item + */ + public function getItemBySku(int $customerId, string $sku): ?Item + { + $result = null; + $items = $this->execute($customerId)->getItemCollection()->getItems(); + foreach ($items as $item) { + if ($item->getProduct()->getData('sku') === $sku) { + $result = $item; + break; + } + } + + return $result; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/SharingTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/SharingTest.php new file mode 100644 index 0000000000000..a96a7e9b4c7b3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/SharingTest.php @@ -0,0 +1,61 @@ +objectManager = Bootstrap::getObjectManager(); + $this->block = $this->objectManager->get(LayoutInterface::class)->createBlock(Sharing::class); + } + + /** + * @return void + */ + public function testDisplayWishListSharingForm(): void + { + $elementsXpath = [ + 'Emails input' => "//form[contains(@class, 'share')]//textarea[@name='emails' and @id='email_address']", + 'Message input' => "//form[contains(@class, 'share')]//textarea[@name='message' and @id='message']", + 'Share button' => "//form[contains(@class, 'share')]//button[contains(@class, 'submit')]" + . "/span[contains(text(), 'Share Wish List')]", + ]; + $blockHtml = $this->block->setTemplate('Magento_Wishlist::sharing.phtml')->toHtml(); + foreach ($elementsXpath as $element => $xpath) { + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath($xpath, $blockHtml), + sprintf("%s was not found.", $element) + ); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/Wishlist/Item/ColumnTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/Wishlist/Item/ColumnTest.php index 668aec616533c..ffce4354dd097 100644 --- a/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/Wishlist/Item/ColumnTest.php +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/Wishlist/Item/ColumnTest.php @@ -3,44 +3,130 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Wishlist\Block\Customer\Wishlist\Item; -class ColumnTest extends \PHPUnit\Framework\TestCase +use Magento\Customer\Model\Session; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\View\Element\Text; +use Magento\Framework\View\LayoutInterface; +use Magento\Framework\View\Result\PageFactory; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Xpath; +use Magento\TestFramework\Wishlist\Model\GetWishlistByCustomerId; +use Magento\Wishlist\Block\Customer\Wishlist\Items; +use PHPUnit\Framework\TestCase; + +/** + * Test wish list item column. + * + * @magentoDbIsolation enabled + * @magentoAppArea frontend + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class ColumnTest extends TestCase { + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var Session */ + private $customerSession; + + /** @var LayoutInterface */ + private $layout; + + /** @var Column */ + private $block; + + /** @var GetWishlistByCustomerId */ + private $getWishlistItemsByCustomerId; + /** - * @var \Magento\Framework\View\LayoutInterface + * @inheritdoc */ - protected $_layout = null; + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->customerSession = $this->objectManager->get(Session::class); + $this->layout = $this->objectManager->get(LayoutInterface::class); + $this->block = $this->layout->addBlock(Column::class, 'test'); + $this->layout->addBlock(Text::class, 'child', 'test'); + $this->getWishlistItemsByCustomerId = $this->objectManager->get(GetWishlistByCustomerId::class); + } /** - * @var \Magento\Wishlist\Block\Customer\Wishlist\Item\Column + * @inheritdoc */ - protected $_block = null; - - protected function setUp() + protected function tearDown() { - $this->_layout = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\View\LayoutInterface::class - ); - $this->_block = $this->_layout->addBlock(\Magento\Wishlist\Block\Customer\Wishlist\Item\Column::class, 'test'); - $this->_layout->addBlock(\Magento\Framework\View\Element\Text::class, 'child', 'test'); + $this->customerSession->setCustomerId(null); + + parent::tearDown(); } /** * @magentoAppIsolation enabled + * + * @return void */ - public function testToHtml() + public function testToHtml(): void { $item = new \StdClass(); - $this->_block->setItem($item); - $this->_block->toHtml(); - $this->assertSame($item, $this->_layout->getBlock('child')->getItem()); + $this->block->setItem($item); + $this->block->toHtml(); + $this->assertSame($item, $this->layout->getBlock('child')->getItem()); } - public function testGetJs() + /** + * @return void + */ + public function testGetJs(): void { $expected = uniqid(); - $this->_layout->getBlock('child')->setJs($expected); - $this->assertEquals($expected, $this->_block->getJs()); + $this->layout->getBlock('child')->setJs($expected); + $this->assertEquals($expected, $this->block->getJs()); + } + + /** + * @magentoDataFixture Magento/Wishlist/_files/wishlist.php + * + * @return void + */ + public function testWishListItemButtons(): void + { + $buttons = [ + "Add to Cart button" => "//button[contains(@class, 'tocart')]/span[contains(text(), 'Add to Cart')]", + "Edit button" => "//a[contains(@class, 'edit')]/span[contains(text(), 'Edit')]", + "Remove item button" => "//a[contains(@class, 'delete')]/span[contains(text(), 'Remove item')]", + ]; + $item = $this->getWishlistItemsByCustomerId->getItemBySku(1, 'simple'); + $this->assertNotNull($item); + $block = $this->getWishListItemsBlock()->getChildBlock('customer.wishlist.item.inner'); + $blockHtml = $block->setItem($item)->toHtml(); + foreach ($buttons as $buttonName => $xpath) { + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath($xpath, $blockHtml), + sprintf("%s wasn't found.", $buttonName) + ); + } + } + + /** + * Get wish list items block. + * + * @return Items + */ + private function getWishListItemsBlock(): Items + { + $page = $this->objectManager->create(PageFactory::class)->create(); + $page->addHandle([ + 'default', + 'wishlist_index_index', + ]); + $page->getLayout()->generateXml(); + + return $page->getLayout()->getBlock('customer.wishlist.items'); } } diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/WishlistTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/WishlistTest.php index 944d2ac6faada..36cd7fe3e4c89 100644 --- a/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/WishlistTest.php +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/WishlistTest.php @@ -15,7 +15,7 @@ use PHPUnit\Framework\TestCase; /** - * Class test my wish list on customer account page. + * Class test block wish list on customer account page. * * @magentoAppArea frontend * @magentoDbIsolation enabled @@ -66,9 +66,11 @@ protected function tearDown() public function testDisplayNumberOfItemsInWishList(): void { $this->customerSession->setCustomerId(1); + $pagerBlockHtml = $this->getWishListBlock()->getChildBlock('wishlist_item_pager')->toHtml(); $this->assertEquals( 1, - Xpath::getElementsCountForXpath(sprintf(self::ITEMS_COUNT_XPATH, 1), $this->getWishListPagerBlockHtml()) + Xpath::getElementsCountForXpath(sprintf(self::ITEMS_COUNT_XPATH, 1), $pagerBlockHtml), + "Element items count wasn't found." ); } @@ -82,27 +84,46 @@ public function testDisplayItemQuantitiesInWishList(): void { $this->markTestSkipped('Test is blocked by issue MC-31595'); $this->customerSession->setCustomerId(1); + $pagerBlockHtml = $this->getWishListBlock()->getChildBlock('wishlist_item_pager')->toHtml(); $this->assertEquals( 1, - Xpath::getElementsCountForXpath(sprintf(self::ITEMS_COUNT_XPATH, 3), $this->getWishListPagerBlockHtml()) + Xpath::getElementsCountForXpath(sprintf(self::ITEMS_COUNT_XPATH, 3), $pagerBlockHtml), + "Element items count wasn't found." ); } /** - * Get wish list pager block html. + * @magentoDataFixture Magento/Wishlist/_files/wishlist.php * - * @return string + * @return void + */ + public function testDisplayActionButtonsInWishList(): void + { + $buttonsXpath = [ + "//button[contains(@class, 'update') and @type='submit']/span[contains(text(), 'Update Wish List')]", + "//button[contains(@class, 'share') and @type='submit']/span[contains(text(), 'Share Wish List')]", + "//button[contains(@class, 'tocart') and @type='button']/span[contains(text(), 'Add All to Cart')]", + ]; + $this->customerSession->setCustomerId(1); + $blockHtml = $this->getWishListBlock()->toHtml(); + foreach ($buttonsXpath as $xpath) { + $this->assertEquals(1, Xpath::getElementsCountForXpath($xpath, $blockHtml)); + } + } + + /** + * Get wish list block. + * + * @return Wishlist */ - private function getWishListPagerBlockHtml(): string + private function getWishListBlock(): Wishlist { $this->page->addHandle([ 'default', 'wishlist_index_index', ]); $this->page->getLayout()->generateXml(); - /** @var Wishlist $customerWishlistBlock */ - $customerWishlistBlock = $this->page->getLayout()->getBlock('customer.wishlist'); - return $customerWishlistBlock->getChildBlock('wishlist_item_pager')->toHtml(); + return $this->page->getLayout()->getBlock('customer.wishlist'); } } diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/AddTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/AddTest.php new file mode 100644 index 0000000000000..82ae8e92d2979 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/AddTest.php @@ -0,0 +1,189 @@ +customerSession = $this->_objectManager->get(Session::class); + $this->getWishlistByCustomerId = $this->_objectManager->get(GetWishlistByCustomerId::class); + $this->productRepository = $this->_objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->escaper = $this->_objectManager->get(Escaper::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->customerSession->setCustomerId(null); + + parent::tearDown(); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_xss.php + * + * @return void + */ + public function testAddActionProductNameXss(): void + { + $this->prepareReferer(); + $this->customerSession->setCustomerId(1); + $product = $this->productRepository->get('product-with-xss'); + $escapedProductName = $this->escaper->escapeHtml($product->getName()); + $this->performAddToWishListRequest(['product' => $product->getId()]); + $this->assertSuccess(1, 1, $escapedProductName); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Wishlist/_files/wishlist_with_configurable_product.php + * @magentoDbIsolation disabled + * + * @return void + */ + public function testAddConfigurableProductToWishList(): void + { + $this->prepareReferer(); + $this->customerSession->setCustomerId(1); + $product = $this->productRepository->get('Configurable product'); + $this->performAddToWishListRequest(['product' => $product->getId()]); + $this->assertSuccess(1, 1, $product->getName()); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Catalog/_files/multiple_products.php + * + * @return void + */ + public function testAddDisabledProductToWishList(): void + { + $expectedMessage = $this->escaper->escapeHtml("We can't specify a product."); + $this->customerSession->setCustomerId(1); + $product = $this->productRepository->get('simple3'); + $this->performAddToWishListRequest(['product' => $product->getId()]); + $this->assertSessionMessages($this->equalTo([(string)__($expectedMessage)]), MessageInterface::TYPE_ERROR); + $this->assertRedirect($this->stringContains('wishlist/')); + } + + /** + * @return void + */ + public function testAddToWishListWithoutParams(): void + { + $this->customerSession->setCustomerId(1); + $this->performAddToWishListRequest([]); + $this->assertSessionMessages($this->isEmpty(), MessageInterface::TYPE_ERROR); + $this->assertSessionMessages($this->isEmpty(), MessageInterface::TYPE_SUCCESS); + $this->assertRedirect($this->stringContains('wishlist/')); + } + + /** + * @return void + */ + public function testAddNotExistingProductToWishList(): void + { + $this->customerSession->setCustomerId(1); + $expectedMessage = $this->escaper->escapeHtml("We can't specify a product."); + $this->performAddToWishListRequest(['product' => 989]); + $this->assertSessionMessages($this->equalTo([(string)__($expectedMessage)]), MessageInterface::TYPE_ERROR); + $this->assertRedirect($this->stringContains('wishlist/')); + } + + /** + * @return void + */ + public function testAddToNotExistingWishList(): void + { + $expectedMessage = $this->escaper->escapeHtml("The requested Wish List doesn't exist."); + $this->customerSession->setCustomerId(1); + $this->performAddToWishListRequest(['wishlist_id' => 989]); + $this->assertSessionMessages($this->equalTo([(string)__($expectedMessage)]), MessageInterface::TYPE_ERROR); + $this->assert404NotFound(); + } + + /** + * Perform request add item to wish list. + * + * @param array $params + * @return void + */ + private function performAddToWishListRequest(array $params): void + { + $this->getRequest()->setParams($params)->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('wishlist/index/add'); + } + + /** + * Assert success response and items count. + * + * @param int $customerId + * @param int $itemsCount + * @param string $productName + * @return void + */ + private function assertSuccess(int $customerId, int $itemsCount, string $productName): void + { + $expectedMessage = sprintf("\n%s has been added to your Wish List.", $productName) + . " Click here to continue shopping."; + $this->assertSessionMessages($this->equalTo([(string)__($expectedMessage)]), MessageInterface::TYPE_SUCCESS); + $wishlist = $this->getWishlistByCustomerId->execute($customerId); + $this->assertCount($itemsCount, $wishlist->getItemCollection()); + $this->assertRedirect($this->stringContains('wishlist/index/index/wishlist_id/' . $wishlist->getId())); + } + + /** + * Prepare referer to test. + * + * @return void + */ + private function prepareReferer(): void + { + $parameters = $this->_objectManager->create(Parameters::class); + $parameters->set('HTTP_REFERER', 'http://localhost/test'); + $this->getRequest()->setServer($parameters); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/AllcartTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/AllcartTest.php new file mode 100644 index 0000000000000..bc589c2791eb5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/AllcartTest.php @@ -0,0 +1,110 @@ +customerSession = $this->_objectManager->get(Session::class); + $this->cart = $this->_objectManager->get(CartFactory::class)->create(); + $this->escaper = $this->_objectManager->get(Escaper::class); + $this->getWishlistByCustomerId = $this->_objectManager->get(GetWishlistByCustomerId::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->customerSession->setCustomerId(null); + + parent::tearDown(); + } + + /** + * @magentoDataFixture Magento/Wishlist/_files/wishlist_with_product_qty_increments.php + * + * @return void + */ + public function testAddProductQtyIncrementToCartFromWishList(): void + { + $this->customerSession->setCustomerId(1); + $this->performAddAllToCartRequest(); + $wishlistCollection = $this->getWishlistByCustomerId->execute(1)->getItemCollection(); + $this->assertCount(1, $wishlistCollection); + $this->assertCount(0, $this->cart->getQuote()->getItemsCollection()); + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'simple'); + $this->assertNotNull($item); + $expectedMessage = $this->escaper->escapeHtml( + sprintf('You can buy this product only in quantities of 5 at a time for "%s".', $item->getName()) + ); + $this->assertSessionMessages($this->equalTo([(string)__($expectedMessage)]), MessageInterface::TYPE_ERROR); + } + + /** + * @magentoDataFixture Magento/Wishlist/_files/wishlist_with_simple_product.php + * + * @return void + */ + public function testAddAllProductToCartFromWishList(): void + { + $this->customerSession->setCustomerId(1); + $this->performAddAllToCartRequest(); + $quoteCollection = $this->cart->getQuote()->getItemsCollection(); + $this->assertCount(1, $quoteCollection); + $item = $quoteCollection->getFirstItem(); + $expectedMessage = $this->escaper->escapeHtml( + sprintf('1 product(s) have been added to shopping cart: "%s".', $item->getName()) + ); + $this->assertSessionMessages($this->equalTo([(string)__($expectedMessage)]), MessageInterface::TYPE_SUCCESS); + } + + /** + * Perform add all products to cart from wish list request. + * + * @return void + */ + private function performAddAllToCartRequest(): void + { + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('wishlist/index/allcart'); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/CartTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/CartTest.php new file mode 100644 index 0000000000000..3681409e40156 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/CartTest.php @@ -0,0 +1,120 @@ +customerSession = $this->_objectManager->get(Session::class); + $this->getWishlistByCustomerId = $this->_objectManager->get(GetWishlistByCustomerId::class); + $this->cartFactory = $this->_objectManager->get(CartFactory::class); + $this->escaper = $this->_objectManager->get(Escaper::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->customerSession->setCustomerId(null); + + parent::tearDown(); + } + + /** + * @magentoDataFixture Magento/Wishlist/_files/wishlist_with_simple_product.php + * + * @return void + */ + public function testAddSimpleProductToCart(): void + { + $this->customerSession->setCustomerId(1); + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'simple-1'); + $this->assertNotNull($item); + $this->performAddToCartRequest(['item' => $item->getId(), 'qty' => 3]); + $message = sprintf('You added %s to your shopping cart.', $item->getName()); + $this->assertSessionMessages($this->equalTo([(string)__($message)]), MessageInterface::TYPE_SUCCESS); + $this->assertCount(0, $this->getWishlistByCustomerId->execute(1)->getItemCollection()); + $cart = $this->cartFactory->create(); + $this->assertEquals(1, $cart->getItemsCount()); + $this->assertEquals(3, $cart->getItemsQty()); + } + + /** + * @magentoDataFixture Magento/Wishlist/_files/wishlist_with_configurable_product.php + * + * @return void + */ + public function testAddItemWithNotChosenOptionToCart(): void + { + $this->customerSession->setCustomerId(1); + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'Configurable product'); + $this->assertNotNull($item); + $this->performAddToCartRequest(['item' => $item->getId(), 'qty' => 1]); + $redirectUrl = sprintf("wishlist/index/configure/id/%s/product_id/%s", $item->getId(), $item->getProductId()); + $this->assertRedirect($this->stringContains($redirectUrl)); + $message = 'You need to choose options for your item.'; + $this->assertSessionMessages($this->equalTo([(string)__($message)]), MessageInterface::TYPE_NOTICE); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * + * @return void + */ + public function testAddNotExistingItemToCart(): void + { + $this->customerSession->setCustomerId(1); + $this->performAddToCartRequest(['item' => 989]); + $this->assertRedirect($this->stringContains('wishlist/index/')); + } + + /** + * Perform request add to cart from wish list. + * + * @param array $params + * @return void + */ + private function performAddToCartRequest(array $params): void + { + $this->getRequest()->setParams($params)->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('wishlist/index/cart'); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/IndexTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/IndexTest.php new file mode 100644 index 0000000000000..b92b2f3e5e85b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/IndexTest.php @@ -0,0 +1,82 @@ +customerSession = $this->_objectManager->get(Session::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->customerSession->setCustomerId(null); + + parent::tearDown(); + } + + /** + * Verify wishlist view action + * + * The following is verified: + * - \Magento\Wishlist\Model\ResourceModel\Item\Collection + * - \Magento\Wishlist\Block\Customer\Wishlist + * - \Magento\Wishlist\Block\Customer\Wishlist\Items + * - \Magento\Wishlist\Block\Customer\Wishlist\Item\Column + * - \Magento\Wishlist\Block\Customer\Wishlist\Item\Column\Cart + * - \Magento\Wishlist\Block\Customer\Wishlist\Item\Column\Comment + * - \Magento\Wishlist\Block\Customer\Wishlist\Button + * - that \Magento\Wishlist\Block\Customer\Wishlist\Item\Options doesn't throw a fatal error + * + * @magentoDataFixture Magento/Wishlist/_files/wishlist.php + * + * @return void + */ + public function testItemColumnBlock(): void + { + $this->customerSession->setCustomerId(1); + $this->dispatch('wishlist/index/index'); + $body = $this->getResponse()->getBody(); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath( + '//img[contains(@src, "small_image.jpg") and @alt = "Simple Product"]', + $body + ) + ); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath( + '//textarea[contains(@name, "description")]', + $body + ) + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/PluginTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/PluginTest.php index 5303c9f352b87..7193791bdbe6c 100644 --- a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/PluginTest.php +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/PluginTest.php @@ -7,12 +7,17 @@ namespace Magento\Wishlist\Controller\Index; +use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Framework\Message\MessageInterface; use Magento\TestFramework\TestCase\AbstractController; use Magento\Customer\Model\Session as CustomerSession; use Magento\Catalog\Api\ProductRepositoryInterface; /** * Test for wishlist plugin before dispatch + * + * @magentoDbIsolation enabled + * @magentoAppArea frontend */ class PluginTest extends AbstractController { @@ -21,13 +26,20 @@ class PluginTest extends AbstractController */ private $customerSession; + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + /** * @inheritdoc */ protected function setUp() { parent::setUp(); + $this->customerSession = $this->_objectManager->get(CustomerSession::class); + $this->productRepository = $this->_objectManager->get(ProductRepositoryInterface::class); } /** @@ -37,20 +49,22 @@ protected function tearDown() { $this->customerSession->logout(); $this->customerSession = null; + parent::tearDown(); } /** * Test for adding product to wishlist with invalidate credentials * - * @return void * @magentoDataFixture Magento/Catalog/_files/product_simple_xss.php * @magentoDataFixture Magento/Customer/_files/customer.php - * @magentoAppArea frontend + * + * @return void */ public function testAddActionProductWithInvalidCredentials(): void { - $this->getRequest()->setMethod('POST'); + $product = $this->productRepository->get('product-with-xss'); + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); $this->getRequest()->setPostValue( [ 'login' => [ @@ -59,14 +73,23 @@ public function testAddActionProductWithInvalidCredentials(): void ], ] ); - - /** @var ProductRepositoryInterface $productRepository */ - $productRepository = $this->_objectManager->get(ProductRepositoryInterface::class); - - $product = $productRepository->get('product-with-xss'); - - $this->dispatch('wishlist/index/add/product/' . $product->getId() . '?nocookie=1'); - + $this->getRequest()->setParams(['product' => $product->getId(), 'nocookie' => 1]); + $this->dispatch('wishlist/index/add'); $this->assertArrayNotHasKey('login', $this->customerSession->getBeforeWishlistRequest()); + $expectedMessage = 'You must login or register to add items to your wishlist.'; + $this->assertSessionMessages($this->equalTo([(string)__($expectedMessage)]), MessageInterface::TYPE_ERROR); + } + + /** + * @magentoConfigFixture current_store wishlist/general/active 0 + * @magentoDataFixture Magento/Customer/_files/customer.php + * + * @return void + */ + public function testWithDisabledWishList(): void + { + $this->customerSession->setCustomerId(1); + $this->dispatch('wishlist/index/index'); + $this->assert404NotFound(); } } diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/RemoveTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/RemoveTest.php new file mode 100644 index 0000000000000..5bd8d006e5fe5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/RemoveTest.php @@ -0,0 +1,79 @@ +customerSession = $this->_objectManager->get(Session::class); + $this->getWishlistByCustomerId = $this->_objectManager->get(GetWishlistByCustomerId::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->customerSession->setCustomerId(null); + + parent::tearDown(); + } + + /** + * @return void + */ + public function testRemoveProductFromWishList(): void + { + $customerId = 1; + $this->customerSession->setCustomerId($customerId); + $item = $this->getWishlistByCustomerId->getItemBySku($customerId, 'simple'); + $this->assertNotNull($item); + $productName = $item->getProduct()->getName(); + $this->getRequest()->setParam('item', $item->getId())->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('wishlist/index/remove'); + $message = sprintf("\n%s has been removed from your Wish List.\n", $productName); + $this->assertSessionMessages($this->equalTo([(string)__($message)]), MessageInterface::TYPE_SUCCESS); + $this->assertCount(0, $this->getWishlistByCustomerId->execute($customerId)->getItemCollection()); + } + + /** + * @return void + */ + public function testRemoveNotExistingItemFromWishList(): void + { + $this->customerSession->setCustomerId(1); + $this->getRequest()->setParams(['item' => 989])->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('wishlist/index/remove'); + $this->assert404NotFound(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/SendTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/SendTest.php new file mode 100644 index 0000000000000..6a89be8bdb3b0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/SendTest.php @@ -0,0 +1,180 @@ +customerSession = $this->_objectManager->get(Session::class); + $this->customerNameGeneration = $this->_objectManager->get(CustomerNameGenerationInterface::class); + $this->productRepository = $this->_objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->transportBuilder = $this->_objectManager->get(TransportBuilderMock::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->customerSession->setCustomerId(null); + + parent::tearDown(); + } + + /** + * @return void + */ + public function testSendWishList(): void + { + $product = $this->productRepository->get('simple'); + $this->customerSession->setCustomerId(1); + $shareMessage = 'Here\'s what I want for my birthday.'; + $postValues = ['emails' => 'test@example.com', 'message' => $shareMessage]; + $this->dispatchSendWishListRequest($postValues); + $this->assertSessionMessages( + $this->equalTo([(string)__('Your wish list has been shared.')]), + MessageInterface::TYPE_SUCCESS + ); + $this->assertNotNull($this->transportBuilder->getSentMessage()); + $messageContent = $this->transportBuilder->getSentMessage()->getBody()->getParts()[0]->getRawContent(); + $this->assertContains($shareMessage, $messageContent); + $this->assertContains( + sprintf( + '%s wants to share this Wish List', + $this->customerNameGeneration->getCustomerName($this->customerSession->getCustomerDataObject()) + ), + $messageContent + ); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath( + sprintf( + "//a[contains(@href, '%s')]/strong[contains(text(), '%s')]", + $product->getProductUrl(), + $product->getName() + ), + $messageContent + ) + ); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath( + "//a[contains(@href, 'wishlist/shared/index/code/fixture_unique_code/')" + . " and contains(text(), 'View all Wish List')]", + $messageContent + ) + ); + } + + /** + * @magentoConfigFixture current_store wishlist/email/number_limit 2 + * + * @return void + */ + public function testSendWishListWithEmailsLimit(): void + { + $this->customerSession->setCustomerId(1); + $postValues = ['emails' => 'test@example.com, test2@example.com, test3@example.com']; + $this->dispatchSendWishListRequest($postValues); + $this->assertResponseWithError('Maximum of 2 emails can be sent.'); + } + + /** + * @magentoConfigFixture current_store wishlist/email/text_limit 10 + * + * @return void + */ + public function testSendWishListWithTextLimit(): void + { + $this->customerSession->setCustomerId(1); + $postValues = ['emails' => 'test@example.com', 'message' => 'Test message']; + $this->dispatchSendWishListRequest($postValues); + $this->assertResponseWithError('Message length must not exceed 10 symbols'); + } + + /** + * @return void + */ + public function testSendWishListWithoutEmails(): void + { + $this->customerSession->setCustomerId(1); + $postValues = ['emails' => '']; + $this->dispatchSendWishListRequest($postValues); + $this->assertResponseWithError('Please enter an email address.'); + } + + /** + * @return void + */ + public function testSendWishListWithInvalidEmail(): void + { + $this->customerSession->setCustomerId(1); + $postValues = ['emails' => 'test @example.com']; + $this->dispatchSendWishListRequest($postValues); + $this->assertResponseWithError('Please enter a valid email address.'); + } + + /** + * Dispatch send wish list request. + * + * @param array $postValues + * @return void + */ + private function dispatchSendWishListRequest(array $postValues): void + { + $this->getRequest()->setPostValue($postValues)->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('wishlist/index/send'); + } + + /** + * Assert error message and redirect. + * + * @param string $message + * @return void + */ + private function assertResponseWithError(string $message): void + { + $this->assertSessionMessages($this->equalTo([__($message)]), MessageInterface::TYPE_ERROR); + $this->assertRedirect($this->stringContains('wishlist/index/share')); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/UpdateItemOptionsTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/UpdateItemOptionsTest.php new file mode 100644 index 0000000000000..40646be11f684 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/UpdateItemOptionsTest.php @@ -0,0 +1,198 @@ +customerSession = $this->_objectManager->get(Session::class); + $this->getWishlistByCustomerId = $this->_objectManager->get(GetWishlistByCustomerId::class); + $this->productRepository = $this->_objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->escaper = $this->_objectManager->get(Escaper::class); + $this->json = $this->_objectManager->get(SerializerInterface::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->customerSession->setCustomerId(null); + + parent::tearDown(); + } + + /** + * @magentoDataFixture Magento/Wishlist/_files/wishlist_with_configurable_product.php + * @magentoDbIsolation disabled + * + * @return void + */ + public function testUpdateItemOptions(): void + { + $this->customerSession->setCustomerId(1); + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'Configurable product'); + $this->assertNotNull($item); + $params = [ + 'id' => $item->getId(), + 'product' => $item->getProductId(), + 'super_attribute' => $this->performConfigurableOption($item->getProduct()), + 'qty' => 5, + ]; + $this->performUpdateWishListItemRequest($params); + $message = sprintf("%s has been updated in your Wish List.", $item->getProduct()->getName()); + $this->assertSessionMessages($this->equalTo([(string)__($message)]), MessageInterface::TYPE_SUCCESS); + $this->assertRedirect($this->stringContains('wishlist/index/index/wishlist_id/' . $item->getWishlistId())); + $this->assertUpdatedItem( + $this->getWishlistByCustomerId->getItemBySku(1, 'Configurable product'), + $params + ); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * + * @return void + */ + public function testUpdateItemOptionsWithoutParams(): void + { + $this->customerSession->setCustomerId(1); + $this->performUpdateWishListItemRequest([]); + $this->assertSessionMessages($this->isEmpty(), MessageInterface::TYPE_ERROR); + $this->assertSessionMessages($this->isEmpty(), MessageInterface::TYPE_SUCCESS); + $this->assertRedirect($this->stringContains('wishlist/')); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * + * @return void + */ + public function testUpdateNotExistingItem(): void + { + $this->customerSession->setCustomerId(1); + $this->performUpdateWishListItemRequest(['product' => 989]); + $message = $this->escaper->escapeHtml("We can't specify a product."); + $this->assertSessionMessages($this->equalTo([(string)__($message)]), MessageInterface::TYPE_ERROR); + $this->assertRedirect($this->stringContains('wishlist/')); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Catalog/_files/multiple_products.php + * + * @return void + */ + public function testUpdateOutOfStockItem(): void + { + $product = $this->productRepository->get('simple3'); + $this->customerSession->setCustomerId(1); + $this->performUpdateWishListItemRequest(['product' => $product->getId()]); + $message = $this->escaper->escapeHtml("We can't specify a product."); + $this->assertSessionMessages($this->equalTo([(string)__($message)]), MessageInterface::TYPE_ERROR); + $this->assertRedirect($this->stringContains('wishlist/')); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute.php + * + * @return void + */ + public function testUpdateItemNotSpecifyAsWishListItem(): void + { + $product = $this->productRepository->get('simple_ms_out_of_stock'); + $this->customerSession->setCustomerId(1); + $this->performUpdateWishListItemRequest(['product' => $product->getId()]); + $message = $this->escaper->escapeHtml("We can't specify a wish list item."); + $this->assertSessionMessages($this->equalTo([(string)__($message)]), MessageInterface::TYPE_ERROR); + $this->assertRedirect($this->stringContains('wishlist/index/index/wishlist_id/')); + } + + /** + * Perform request update wish list item. + * + * @param array $params + * @return void + */ + private function performUpdateWishListItemRequest(array $params): void + { + $this->getRequest()->setParams($params)->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('wishlist/index/updateItemOptions'); + } + + /** + * Assert updated item in wish list. + * + * @param Item $item + * @param array $expectedData + * @return void + */ + private function assertUpdatedItem(Item $item, array $expectedData): void + { + $this->assertEquals($expectedData['qty'], $item->getQty()); + $buyRequestOption = $this->json->unserialize($item->getOptionByCode('info_buyRequest')->getValue()); + foreach ($expectedData as $key => $value) { + $this->assertEquals($value, $buyRequestOption[$key]); + } + } + + /** + * Perform configurable option to select. + * + * @param ProductInterface $product + * @return array + */ + private function performConfigurableOption(ProductInterface $product): array + { + $configurableOptions = $product->getTypeInstance()->getConfigurableOptions($product); + $attributeId = key($configurableOptions); + $option = reset($configurableOptions[$attributeId]); + + return [$attributeId => $option['value_index']]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/UpdateTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/UpdateTest.php new file mode 100644 index 0000000000000..8126ec71eb7db --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/Index/UpdateTest.php @@ -0,0 +1,98 @@ +customerSession = $this->_objectManager->get(Session::class); + $this->getWishlistByCustomerId = $this->_objectManager->get(GetWishlistByCustomerId::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->customerSession->setCustomerId(null); + + parent::tearDown(); + } + + /** + * @return void + */ + public function testUpdateWishListItem(): void + { + $this->customerSession->setCustomerId(1); + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'simple'); + $this->assertNotNull($item); + $params = ['description' => [$item->getId() => 'Some description.'], 'qty' => [$item->getId() => 5]]; + $this->performUpdateWishListItemRequest($params); + $message = sprintf("%s has been updated in your Wish List.", $item->getProduct()->getName()); + $this->assertSessionMessages($this->equalTo([(string)__($message)]), MessageInterface::TYPE_SUCCESS); + $this->assertRedirect($this->stringContains('wishlist/index/index/wishlist_id/' . $item->getWishlistId())); + $updatedItem = $this->getWishlistByCustomerId->getItemBySku(1, 'simple'); + $this->assertNotNull($updatedItem); + $this->assertEquals(5, $updatedItem->getQty()); + $this->assertEquals('Some description.', $updatedItem->getDescription()); + } + + /** + * @return void + */ + public function testUpdateWishListItemZeroQty(): void + { + $this->customerSession->setCustomerId(1); + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'simple'); + $this->assertNotNull($item); + $params = ['description' => [$item->getId() => ''], 'qty' => [$item->getId() => 0]]; + $this->performUpdateWishListItemRequest($params); + $message = sprintf("%s has been updated in your Wish List.", $item->getProduct()->getName()); + $this->assertSessionMessages($this->equalTo([(string)__($message)]), MessageInterface::TYPE_SUCCESS); + $this->assertRedirect($this->stringContains('wishlist/index/index/wishlist_id/' . $item->getWishlistId())); + $this->assertCount(0, $this->getWishlistByCustomerId->execute(1)->getItemCollection()); + } + + /** + * Perform update wish list item request. + * + * @param array $params + * @return void + */ + private function performUpdateWishListItemRequest(array $params): void + { + $this->getRequest()->setPostValue($params)->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('wishlist/index/update'); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/IndexTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/IndexTest.php deleted file mode 100644 index d225b40dc39da..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/IndexTest.php +++ /dev/null @@ -1,190 +0,0 @@ -createMock(\Psr\Log\LoggerInterface::class); - $this->_customerSession = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Customer\Model\Session::class, - [$logger] - ); - /** @var \Magento\Customer\Api\AccountManagementInterface $service */ - $service = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Customer\Api\AccountManagementInterface::class - ); - $customer = $service->authenticate('customer@example.com', 'password'); - $this->_customerSession->setCustomerDataAsLoggedIn($customer); - - $this->_customerViewHelper = $this->_objectManager->create(\Magento\Customer\Helper\View::class); - - $this->_messages = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\Message\ManagerInterface::class - ); - } - - protected function tearDown() - { - $this->_customerSession->logout(); - $this->_customerSession = null; - parent::tearDown(); - } - - /** - * Verify wishlist view action - * - * The following is verified: - * - \Magento\Wishlist\Model\ResourceModel\Item\Collection - * - \Magento\Wishlist\Block\Customer\Wishlist - * - \Magento\Wishlist\Block\Customer\Wishlist\Items - * - \Magento\Wishlist\Block\Customer\Wishlist\Item\Column - * - \Magento\Wishlist\Block\Customer\Wishlist\Item\Column\Cart - * - \Magento\Wishlist\Block\Customer\Wishlist\Item\Column\Comment - * - \Magento\Wishlist\Block\Customer\Wishlist\Button - * - that \Magento\Wishlist\Block\Customer\Wishlist\Item\Options doesn't throw a fatal error - * - * @magentoDataFixture Magento/Wishlist/_files/wishlist.php - */ - public function testItemColumnBlock() - { - $this->dispatch('wishlist/index/index'); - $body = $this->getResponse()->getBody(); - $this->assertEquals( - 1, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath( - '//img[contains(@src, "small_image.jpg") and @alt = "Simple Product"]', - $body - ) - ); - $this->assertEquals( - 1, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath( - '//textarea[contains(@name, "description")]', - $body - ) - ); - } - - /** - * @magentoDataFixture Magento/Catalog/_files/product_simple_xss.php - * @magentoDataFixture Magento/Customer/_files/customer.php - * @magentoAppArea frontend - */ - public function testAddActionProductNameXss() - { - /** @var \Magento\Framework\Data\Form\FormKey $formKey */ - $formKey = $this->_objectManager->get(\Magento\Framework\Data\Form\FormKey::class); - $this->getRequest()->setMethod('POST'); - $this->getRequest()->setPostValue( - [ - 'form_key' => $formKey->getFormKey(), - ] - ); - - /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ - $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); - - $product = $productRepository->get('product-with-xss'); - - $this->dispatch('wishlist/index/add/product/' . $product->getId() . '?nocookie=1'); - - $this->assertSessionMessages( - $this->equalTo( - [ - "\n<script>alert("xss");</script> has been added to your Wish List. " - . 'Click here to continue shopping.', - ] - ), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - } - - /** - * @magentoDbIsolation disabled - * @magentoDataFixture Magento/Wishlist/_files/wishlist_with_product_qty_increments.php - */ - public function testAllcartAction() - { - $formKey = $this->_objectManager->get(\Magento\Framework\Data\Form\FormKey::class)->getFormKey(); - $this->getRequest()->setMethod('POST'); - $this->getRequest()->setParam('form_key', $formKey); - $this->dispatch('wishlist/index/allcart'); - - /** @var \Magento\Checkout\Model\Cart $cart */ - $cart = $this->_objectManager->get(\Magento\Checkout\Model\Cart::class); - $quoteCount = $cart->getQuote()->getItemsCollection()->count(); - - $this->assertEquals(0, $quoteCount); - $this->assertSessionMessages( - $this->contains( - htmlspecialchars( - 'You can buy this product only in quantities of 5 at a time for "Simple Product".' - ) - ), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR - ); - } - - /** - * @magentoDataFixture Magento/Wishlist/_files/wishlist.php - */ - public function testSendAction() - { - \Magento\TestFramework\Helper\Bootstrap::getInstance() - ->loadArea(\Magento\Framework\App\Area::AREA_FRONTEND); - - $request = [ - 'form_key' => $this->_objectManager->get(\Magento\Framework\Data\Form\FormKey::class)->getFormKey(), - 'emails' => 'test@tosend.com', - 'message' => 'message', - 'rss_url' => null, // no rss - ]; - - $this->getRequest()->setPostValue($request); - $this->getRequest()->setMethod('POST'); - - $this->_objectManager->get(\Magento\Framework\Registry::class)->register( - 'wishlist', - $this->_objectManager->get(\Magento\Wishlist\Model\Wishlist::class)->loadByCustomerId(1) - ); - $this->dispatch('wishlist/index/send'); - - /** @var \Magento\TestFramework\Mail\Template\TransportBuilderMock $transportBuilder */ - $transportBuilder = $this->_objectManager->get( - \Magento\TestFramework\Mail\Template\TransportBuilderMock::class - ); - - $actualResult = $transportBuilder->getSentMessage()->getBody()->getParts()[0]->getRawContent(); - - $this->assertStringMatchesFormat( - '%A' . $this->_customerViewHelper->getCustomerName($this->_customerSession->getCustomerDataObject()) - . ' wants to share this Wish List%A', - $actualResult - ); - } -} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Model/ItemTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Model/ItemTest.php index 896b59c7983fe..afd15929ae685 100644 --- a/dev/tests/integration/testsuite/Magento/Wishlist/Model/ItemTest.php +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Model/ItemTest.php @@ -3,57 +3,94 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Wishlist\Model; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product\Exception as ProductException; +use Magento\Checkout\Model\CartFactory; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\DataObjectFactory; +use Magento\TestFramework\Wishlist\Model\GetWishlistByCustomerId; +use Magento\Wishlist\Model\Item\OptionFactory; +use PHPUnit\Framework\TestCase; + /** - * Item test class. + * Tests for wish list item model. + * + * @magentoDbIsolation enabled + * @magentoAppIsolation disabled */ -class ItemTest extends \PHPUnit\Framework\TestCase +class ItemTest extends TestCase { - /** - * @var \Magento\Framework\App\ObjectManager - */ + /** @var ObjectManager */ private $objectManager; - /** - * @var \Magento\Wishlist\Model\Item - */ + /** @var Item */ private $model; + /** @var DataObjectFactory */ + private $dataObjectFactory; + + /** @var OptionFactory */ + private $optionFactory; + + /** @var GetWishlistByCustomerId */ + private $getWishlistByCustomerId; + + /** @var CartFactory */ + private $cartFactory; + + /** @var ProductRepositoryInterface */ + private $productRepository; + + /** @var ItemFactory */ + private $itemFactory; + /** - * {@inheritDoc} + * @inheritdoc */ public function setUp() { - $this->objectManager = \Magento\Framework\App\ObjectManager::getInstance(); - $this->model = $this->objectManager->get(\Magento\Wishlist\Model\Item::class); + parent::setUp(); + + $this->objectManager = ObjectManager::getInstance(); + $this->dataObjectFactory = $this->objectManager->get(DataObjectFactory::class); + $this->model = $this->objectManager->get(Item::class); + $this->itemFactory = $this->objectManager->get(ItemFactory::class); + $this->optionFactory = $this->objectManager->get(OptionFactory::class); + $this->getWishlistByCustomerId = $this->objectManager->get(GetWishlistByCustomerId::class); + $this->cartFactory = $this->objectManager->get(CartFactory::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); } /** - * @magentoDataFixture Magento/Catalog/_files/product_simple.php - * @magentoAppIsolation enabled - * @magentoDbIsolation enabled + * @inheritdoc */ - public function testBuyRequest() + protected function tearDown() { - /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ - $productRepository = $this->objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); - $product = $productRepository->getById(1); + $this->cartFactory->create()->truncate(); - /** @var \Magento\Wishlist\Model\Item\Option $option */ - $option = $this->objectManager->create( - \Magento\Wishlist\Model\Item\Option::class, + parent::tearDown(); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * + * @return void + */ + public function testBuyRequest(): void + { + $product = $this->productRepository->get('simple'); + $option = $this->optionFactory->create( ['data' => ['code' => 'info_buyRequest', 'value' => '{"qty":23}']] ); $option->setProduct($product); $this->model->addOption($option); - - // Assert getBuyRequest method $buyRequest = $this->model->getBuyRequest(); $this->assertEquals($buyRequest->getOriginalQty(), 23); - - // Assert mergeBuyRequest method $this->model->mergeBuyRequest(['qty' => 11, 'additional_data' => 'some value']); $buyRequest = $this->model->getBuyRequest(); $this->assertEquals( @@ -62,18 +99,87 @@ public function testBuyRequest() ); } - public function testSetBuyRequest() + /** + * @return void + */ + public function testSetBuyRequest(): void { - $buyRequest = $this->objectManager->create( - \Magento\Framework\DataObject::class, + $buyRequest = $this->dataObjectFactory->create( ['data' => ['field_1' => 'some data', 'field_2' => 234]] ); - $this->model->setBuyRequest($buyRequest); - - $this->assertEquals( + $this->assertJsonStringEqualsJsonString( '{"field_1":"some data","field_2":234,"id":null}', $this->model->getData('buy_request') ); } + + /** + * @magentoDataFixture Magento/Wishlist/_files/wishlist_with_simple_product.php + * @magentoDbIsolation disabled + * + * @return void + */ + public function testAddItemToCart(): void + { + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'simple-1'); + $this->assertNotNull($item); + $cart = $this->cartFactory->create(); + $this->assertTrue($item->addToCart($cart)); + $this->assertCount(1, $cart->getQuote()->getItemsCollection()); + $this->assertCount(1, $this->getWishlistByCustomerId->execute(1)->getItemCollection()); + } + + /** + * @magentoDataFixture Magento/Wishlist/_files/wishlist_with_simple_product.php + * @magentoDbIsolation disabled + * + * @return void + */ + public function testAddItemToCartAndDeleteFromWishList(): void + { + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'simple-1'); + $this->assertNotNull($item); + $cart = $this->cartFactory->create(); + $item->addToCart($cart, true); + $this->assertCount(1, $cart->getQuote()->getItemsCollection()); + $this->assertCount(0, $this->getWishlistByCustomerId->execute(1)->getItemCollection()); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php + * + * @return void + */ + public function testAddOutOfStockItemToCart(): void + { + $product = $this->productRepository->get('simple-out-of-stock'); + $item = $this->itemFactory->create()->setProduct($product); + $this->expectExceptionObject(new ProductException(__('Product is not salable.'))); + $item->addToCart($this->cartFactory->create()); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/multiple_products.php + * + * @return void + */ + public function testAddDisabledItemToCart(): void + { + $product = $this->productRepository->get('simple3'); + $item = $this->itemFactory->create()->setProduct($product); + $this->assertFalse($item->addToCart($this->cartFactory->create())); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/simple_products_not_visible_individually.php + * + * @return void + */ + public function testAddNotVisibleItemToCart(): void + { + $product = $this->productRepository->get('simple_not_visible_1'); + $item = $this->itemFactory->create()->setProduct($product)->setStoreId($product->getStoreId()); + $this->assertFalse($item->addToCart($this->cartFactory->create())); + } } diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Model/WishlistTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Model/WishlistTest.php index b684da05dd254..f12299b32945d 100644 --- a/dev/tests/integration/testsuite/Magento/Wishlist/Model/WishlistTest.php +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Model/WishlistTest.php @@ -3,63 +3,86 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Wishlist\Model; +use Magento\Bundle\Model\Product\OptionList; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus; use Magento\Framework\App\ObjectManager; -use Magento\Framework\DataObject; +use Magento\Framework\DataObjectFactory; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\TestFramework\Wishlist\Model\GetWishlistByCustomerId; +use PHPUnit\Framework\TestCase; -class WishlistTest extends \PHPUnit\Framework\TestCase +/** + * Tests for wish list model. + * + * @magentoDbIsolation enabled + * @magentoAppIsolation disabled + */ +class WishlistTest extends TestCase { - /** - * @var ObjectManager - */ + /** @var ObjectManager */ private $objectManager; - /** - * @var Wishlist - */ - private $wishlist; + /** @var WishlistFactory */ + private $wishlistFactory; + + /** @var GetWishlistByCustomerId */ + private $getWishlistByCustomerId; + + /** @var ProductRepositoryInterface */ + private $productRepository; + + /** @var DataObjectFactory */ + private $dataObjectFactory; + + /** @var SerializerInterface */ + private $json; /** - * {@inheritDoc} + * @inheritdoc */ protected function setUp() { $this->objectManager = ObjectManager::getInstance(); - $this->wishlist = $this->objectManager->get(Wishlist::class); + $this->wishlistFactory = $this->objectManager->get(WishlistFactory::class); + $this->getWishlistByCustomerId = $this->objectManager->get(GetWishlistByCustomerId::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->dataObjectFactory = $this->objectManager->get(DataObjectFactory::class); + $this->json = $this->objectManager->get(SerializerInterface::class); } /** * @magentoDataFixture Magento/Catalog/_files/product_simple.php * @magentoDataFixture Magento/Customer/_files/customer.php - * @magentoAppIsolation enabled - * @magentoDbIsolation enabled + * + * @return void */ - public function testAddNewItem() + public function testAddNewItem(): void { $productSku = 'simple'; $customerId = 1; - /** @var ProductRepositoryInterface $productRepository */ - $productRepository = $this->objectManager->create(ProductRepositoryInterface::class); - $product = $productRepository->get($productSku); - $this->wishlist->loadByCustomerId($customerId, true); - $this->wishlist->addNewItem( + $product = $this->productRepository->get($productSku); + $wishlist = $this->getWishlistByCustomerId->execute($customerId); + $wishlist->addNewItem( $product, '{"qty":2}' ); - $this->wishlist->addNewItem( + $wishlist->addNewItem( $product, ['qty' => 3] ); - $this->wishlist->addNewItem( + $wishlist->addNewItem( $product, - new DataObject(['qty' => 4]) + $this->dataObjectFactory->create(['data' => ['qty' => 4]]) ); - $this->wishlist->addNewItem($product); - /** @var Item $wishlistItem */ - $wishlistItem = $this->wishlist->getItemCollection()->getFirstItem(); + $wishlist->addNewItem($product); + $wishlistItem = $this->getWishlistByCustomerId->getItemBySku(1, $productSku); $this->assertInstanceOf(Item::class, $wishlistItem); $this->assertEquals($wishlistItem->getQty(), 10); } @@ -67,58 +90,169 @@ public function testAddNewItem() /** * @magentoDataFixture Magento/Catalog/_files/product_simple.php * @magentoDataFixture Magento/Customer/_files/customer.php - * @magentoAppIsolation enabled - * @magentoDbIsolation enabled - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Invalid wishlist item configuration. + * + * @return void */ - public function testAddNewItemInvalidWishlistItemConfiguration() + public function testAddNewItemInvalidWishlistItemConfiguration(): void { $productSku = 'simple'; $customerId = 1; - /** @var ProductRepositoryInterface $productRepository */ - $productRepository = $this->objectManager->create(ProductRepositoryInterface::class); - $product = $productRepository->get($productSku); - $this->wishlist->loadByCustomerId($customerId, true); - $this->wishlist->addNewItem( - $product, - '{"qty":2' - ); - $this->wishlist->addNewItem($product); + $product = $this->productRepository->get($productSku); + $wishlist = $this->getWishlistByCustomerId->execute($customerId); + $this->expectExceptionObject(new \InvalidArgumentException('Invalid wishlist item configuration.')); + $wishlist->addNewItem($product, '{"qty":2'); + } + + /** + * @magentoDataFixture Magento/Wishlist/_files/wishlist.php + * + * @return void + */ + public function testGetItemCollection(): void + { + $productSku = 'simple'; + $item = $this->getWishlistByCustomerId->getItemBySku(1, $productSku); + $this->assertNotNull($item); } /** - * @magentoDbIsolation disabled * @magentoDataFixture Magento/Wishlist/_files/wishlist.php + * + * @return void */ - public function testGetItemCollection() + public function testGetItemCollectionWithDisabledProduct(): void { $productSku = 'simple'; $customerId = 1; + $product = $this->productRepository->get($productSku); + $product->setStatus(ProductStatus::STATUS_DISABLED); + $this->productRepository->save($product); + $this->assertEmpty($this->getWishlistByCustomerId->execute($customerId)->getItemCollection()->getItems()); + } - $this->wishlist->loadByCustomerId($customerId, true); - $itemCollection = $this->wishlist->getItemCollection(); - /** @var \Magento\Wishlist\Model\Item $item */ - $item = $itemCollection->getFirstItem(); - $this->assertEquals($productSku, $item->getProduct()->getSku()); + /** + * @magentoDataFixture Magento/ConfigurableProduct/_files/configurable_product_with_two_child_products.php + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDbIsolation disabled + * + * @return void + */ + public function testAddConfigurableProductToWishList(): void + { + $configurableProduct = $this->productRepository->get('Configurable product'); + $configurableOptions = $configurableProduct->getTypeInstance()->getConfigurableOptions($configurableProduct); + $attributeId = key($configurableOptions); + $option = reset($configurableOptions[$attributeId]); + $buyRequest = ['super_attribute' => [$attributeId => $option['value_index']]]; + $wishlist = $this->getWishlistByCustomerId->execute(1); + $wishlist->addNewItem($configurableProduct, $buyRequest); + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'Configurable product'); + $this->assertNotNull($item); + $this->assertWishListItem($item, $option['sku'], $buyRequest); } /** + * @magentoDataFixture Magento/Bundle/_files/fixed_bundle_product_without_discounts.php + * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDbIsolation disabled + * + * @return void + */ + public function testAddBundleProductToWishList(): void + { + $bundleProduct = $this->productRepository->get('fixed_bundle_product_without_discounts'); + $bundleOptionList = $this->objectManager->create(OptionList::class); + $bundleOptions = $bundleOptionList->getItems($bundleProduct); + $option = reset($bundleOptions); + $productLinks = $option->getProductLinks(); + $this->assertNotNull($productLinks[0]); + $buyRequest = ['bundle_option' => [$option->getOptionId() => $productLinks[0]->getId()]]; + $skuWithChosenOption = implode('-', [$bundleProduct->getSku(), $productLinks[0]->getSku()]); + $wishlist = $this->getWishlistByCustomerId->execute(1); + $wishlist->addNewItem($bundleProduct, $buyRequest); + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'fixed_bundle_product_without_discounts'); + $this->assertNotNull($item); + $this->assertWishListItem($item, $skuWithChosenOption, $buyRequest); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * + * @return void + */ + public function testAddNotExistingItemToWishList(): void + { + $wishlist = $this->getWishlistByCustomerId->execute(1); + $this->expectExceptionObject(new LocalizedException(__('Cannot specify product.'))); + $wishlist->addNewItem(989); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Catalog/_files/product_out_of_stock_with_multiselect_attribute.php + * + * @return void + */ + public function testAddOutOfStockItemToWishList(): void + { + $product = $this->productRepository->get('simple_ms_out_of_stock'); + $wishlist = $this->getWishlistByCustomerId->execute(1); + $this->expectExceptionObject(new LocalizedException(__('Cannot add product without stock to wishlist.'))); + $wishlist->addNewItem($product); + } + + /** * @magentoDataFixture Magento/Wishlist/_files/wishlist.php + * + * @return void */ - public function testGetItemCollectionWithDisabledProduct() + public function testUpdateItemQtyInWishList(): void { - $productSku = 'simple'; - $customerId = 1; + $wishlist = $this->getWishlistByCustomerId->execute(1); + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'simple'); + $this->assertNotNull($item); + $buyRequest = $this->dataObjectFactory->create(['data' => ['qty' => 55]]); + $wishlist->updateItem($item->getId(), $buyRequest); + $updatedItem = $this->getWishlistByCustomerId->getItemBySku(1, 'simple'); + $this->assertEquals(55, $updatedItem->getQty()); + } - $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); - $product = $productRepository->get($productSku); - $product->setStatus(ProductStatus::STATUS_DISABLED); - $productRepository->save($product); + /** + * @return void + */ + public function testUpdateNotExistingItemInWishList(): void + { + $this->expectExceptionObject(new LocalizedException(__('We can\'t specify a wish list item.'))); + $this->wishlistFactory->create()->updateItem(989, []); + } - $this->wishlist->loadByCustomerId($customerId, true); - $itemCollection = $this->wishlist->getItemCollection(); - $this->assertEmpty($itemCollection->getItems()); + /** + * @magentoDataFixture Magento/Wishlist/_files/wishlist.php + * + * @return void + */ + public function testUpdateNotExistingProductInWishList(): void + { + $wishlist = $this->getWishlistByCustomerId->execute(1); + $item = $this->getWishlistByCustomerId->getItemBySku(1, 'simple'); + $this->assertNotNull($item); + $item->getProduct()->setId(null); + $this->expectExceptionObject(new LocalizedException(__('The product does not exist.'))); + $wishlist->updateItem($item, []); + } + + /** + * Assert item in wish list. + * + * @param Item $item + * @param string $itemSku + * @param array $buyRequest + * @return void + */ + private function assertWishListItem(Item $item, string $itemSku, array $buyRequest): void + { + $this->assertEquals($itemSku, $item->getProduct()->getSku()); + $buyRequestOption = $item->getOptionByCode('info_buyRequest'); + $this->assertEquals($buyRequest, $this->json->unserialize($buyRequestOption->getValue())); } } diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_shared_rollback.php b/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_shared_rollback.php new file mode 100644 index 0000000000000..24bbccd5739f4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_shared_rollback.php @@ -0,0 +1,9 @@ +get(WishlistFactory::class); +$wishlist = $wishlistFactory->create(); +$wishlist->loadByCustomerId($customer->getId(), true); +$product = $productRepository->get('Configurable product'); +$wishlist->addNewItem($product); diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_with_configurable_product_rollback.php b/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_with_configurable_product_rollback.php new file mode 100644 index 0000000000000..776d17137db30 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_with_configurable_product_rollback.php @@ -0,0 +1,10 @@ +get(WishlistFactory::class); +$wishlist = $wishlistFactory->create(); +$wishlist->loadByCustomerId($customer->getId(), true); +$wishlist->addNewItem($product); diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_with_simple_product_rollback.php b/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_with_simple_product_rollback.php new file mode 100644 index 0000000000000..ffa99feba6652 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist_with_simple_product_rollback.php @@ -0,0 +1,9 @@ + Date: Mon, 16 Mar 2020 15:09:29 +0200 Subject: [PATCH 6/8] MC-32124: Admin: Create/update bundle product --- .../Product/AbstractBundleProductSaveTest.php | 252 ++++++++++++++++ .../Product/DynamicBundleProductTest.php | 269 ++++++++++++++++++ .../Product/FixedBundleProductTest.php | 226 +++++++++++++++ 3 files changed, 747 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/AbstractBundleProductSaveTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/DynamicBundleProductTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/FixedBundleProductTest.php diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/AbstractBundleProductSaveTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/AbstractBundleProductSaveTest.php new file mode 100644 index 0000000000000..3ce3181b9c803 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/AbstractBundleProductSaveTest.php @@ -0,0 +1,252 @@ +productRepository = $this->_objectManager->get(ProductRepositoryInterface::class); + $this->eavConfig = $this->_objectManager->get(Config::class); + $this->productResource = $this->_objectManager->get(ProductResource::class); + $this->productToDelete = $this->getStaticProductData()['sku']; + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + if ($this->productToDelete) { + $this->productRepository->deleteById($this->productToDelete); + } + + parent::tearDown(); + } + + /** + * Retrieve default product attribute set id. + * + * @return int + */ + protected function getDefaultAttributeSetId(): int + { + return (int)$this->eavConfig->getEntityType(ProductAttributeInterface::ENTITY_TYPE_CODE) + ->getDefaultAttributeSetId(); + } + + /** + * Prepare request + * + * @param array $post + * @param int|null $id + * @return array + */ + protected function prepareRequestData(array $post, ?int $id = null): array + { + $post = $this->preparePostParams($post); + $this->setRequestparams($post, $id); + + return $post; + } + + /** + * Prepare and assert bundle options + * + * @param array $bundleOptions + * @return void + */ + protected function assertBundleOptions(array $bundleOptions): void + { + $mainProduct = $this->productRepository->get($this->getStaticProductData()['sku'], false, null, true); + $optionsCollection = $mainProduct->getTypeInstance()->getOptionsCollection($mainProduct); + $selectionCollection = $mainProduct->getTypeInstance() + ->getSelectionsCollection($optionsCollection->getAllIds(), $mainProduct); + $this->assertOptionsData($bundleOptions, $optionsCollection, $selectionCollection); + } + + /** + * Prepare post params before dispatch + * + * @param array $post + * @return array + */ + private function preparePostParams(array $post): array + { + $post['product'] = $this->getStaticProductData(); + foreach ($post['bundle_options']['bundle_options'] as &$bundleOption) { + $bundleOption = $this->prepareOptionByType($bundleOption['type'], $bundleOption); + $productIdsBySkus = $this->productResource->getProductsIdsBySkus( + array_column($bundleOption['bundle_selections'], 'sku') + ); + foreach ($bundleOption['bundle_selections'] as &$bundleSelection) { + $bundleSelection = $this->prepareSelection($productIdsBySkus, $bundleSelection); + } + } + + return $post; + } + + /** + * Prepare option params + * + * @param string $type + * @param array $option + * @return array + */ + private function prepareOptionByType(string $type, array $option): array + { + $option['required'] = '1'; + $option['delete'] = ''; + $option['title'] = $option['title'] ?? $type . ' Option Title'; + + return $option; + } + + /** + * Prepare selection params + * + * @param array $productIdsBySkus + * @param array $selection + * @return array + */ + private function prepareSelection(array $productIdsBySkus, array $selection): array + { + $staticData = [ + 'price' => '10', + 'selection_qty' => '5', + 'selection_can_change_qty' => '0' + ]; + $selection['product_id'] = $productIdsBySkus[$selection['sku']]; + $selection = array_merge($selection, $staticData); + + return $selection; + } + + /** + * Assert bundle options data + * + * @param array $expectedOptions + * @param OptionCollection $actualOptions + * @param SelectionCollection $selectionCollection + * @return void + */ + private function assertOptionsData( + array $expectedOptions, + OptionCollection $actualOptions, + SelectionCollection $selectionCollection + ): void { + $this->assertCount(count($expectedOptions['bundle_options']), $actualOptions); + foreach ($expectedOptions['bundle_options'] as $expectedOption) { + $optionToCheck = $actualOptions->getItemByColumnValue('title', $expectedOption['title']); + $this->assertNotNull($optionToCheck->getId()); + $selectionToCheck = $selectionCollection->getItemsByColumnValue('option_id', $optionToCheck->getId()); + $this->assertCount(count($expectedOption['bundle_selections']), $selectionToCheck); + $this->assertSelections($expectedOption['bundle_selections'], $selectionToCheck); + unset($expectedOption['delete'], $expectedOption['bundle_selections']); + foreach ($expectedOption as $key => $value) { + $this->assertEquals($value, $optionToCheck->getData($key)); + } + } + } + + /** + * Assert selections data + * + * @param array $expectedSelections + * @param array $actualSelections + * @return void + */ + private function assertSelections(array $expectedSelections, array $actualSelections): void + { + foreach ($expectedSelections as $expectedSelection) { + $actualSelectionToCheck = $this->getSelectionByProductSku($expectedSelection['sku'], $actualSelections); + $this->assertNotNull($actualSelectionToCheck); + foreach ($expectedSelection as $key => $value) { + $this->assertEquals($value, $actualSelectionToCheck->getData($key)); + } + } + } + + /** + * Get selection by product sku + * + * @param string $sku + * @param array $actualSelections + * @return ProductInterface + */ + private function getSelectionByProductSku(string $sku, array $actualSelections): ProductInterface + { + $item = null; + foreach ($actualSelections as $selection) { + if ($selection->getSku() === $sku) { + $item = $selection; + break; + } + } + + return $item; + } + + /** + * Set request parameters + * + * @param array $post + * @param int|null $id + * @return void + */ + private function setRequestParams(array $post, ?int $id): void + { + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $params = ['type' => Type::TYPE_CODE, 'set' => $this->getDefaultAttributeSetId()]; + if ($id) { + $params['id'] = $id; + } + $this->getRequest()->setParams($params); + $this->getRequest()->setPostValue('product', $post['product']); + $this->getRequest()->setPostValue('bundle_options', $post['bundle_options']); + } + + /** + * Get main product data + * + * @return array + */ + abstract protected function getStaticProductData(): array; +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/DynamicBundleProductTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/DynamicBundleProductTest.php new file mode 100644 index 0000000000000..988baf91981bc --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/DynamicBundleProductTest.php @@ -0,0 +1,269 @@ +prepareRequestData($post); + $this->dispatch('backend/catalog/product/save'); + $this->assertBundleOptions($post['bundle_options']); + } + + /** + * @return array + */ + public function bundleProductDataProvider(): array + { + return [ + 'with_dropdown_option' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'select', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + ], + ], + ], + ], + ], + ], + 'with_radio_buttons_option' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'radio', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + ], + ], + ], + ], + ], + ], + 'with_checkbox_option' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'checkbox', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + ], + ], + ], + ], + ], + ], + 'with_multiselect_option' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'multi', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + ], + ], + ], + ], + ], + ], + ]; + } + + /** + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_duplicated.php + * + * @dataProvider multiOptionsDataProvider + * + * @param array $post + * @return void + */ + public function testBundleProductSaveMultiOptions(array $post): void + { + $post = $this->prepareRequestData($post); + $this->dispatch('backend/catalog/product/save'); + $this->assertBundleOptions($post['bundle_options']); + } + + /** + * @return array + */ + public function multiOptionsDataProvider(): array + { + return [ + 'with_two_options_few_selections' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'select', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + [ + 'name' => 'Simple Product', + 'sku' => 'simple-1', + ], + ], + ], + [ + 'type' => 'checkbox', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product', + 'sku' => 'simple-1', + ], + ], + ], + ], + ], + ], + ], + ]; + } + + /** + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @dataProvider emptyOptionTitleDataProvider + * + * @param array $post + * @return void + */ + public function testProductSaveMissedOptionTitle(array $post): void + { + $this->productToDelete = null; + $post = $this->prepareRequestData($post); + $this->dispatch('backend/catalog/product/save'); + $this->assertSessionMessages($this->equalTo(["The option couldn't be saved."])); + } + + /** + * @return array + */ + public function emptyOptionTitleDataProvider(): array + { + return [ + 'empty_option_title' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'title' => '', + 'type' => 'multi', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + ], + ], + ], + ], + ], + ], + ]; + } + + /** + * @magentoDataFixture Magento/Bundle/_files/bundle_product_checkbox_options.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @dataProvider updateProductDataProvider + * + * @param array $post + * @return void + */ + public function testUpdateProduct(array $post): void + { + $id = $this->productRepository->get('bundle-product-checkbox-options')->getId(); + $post = $this->prepareRequestData($post, (int)$id); + $this->dispatch('backend/catalog/product/save'); + $this->assertBundleOptions($post['bundle_options']); + } + + /** + * @return array + */ + public function updateProductDataProvider(): array + { + return [ + 'update_existing_product' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'multi', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + ], + ], + ], + ], + ], + ], + ]; + } + + /** + * @inheritdoc + */ + protected function getStaticProductData(): array + { + return [ + 'sku' => 'bundle-test-product', + 'name' => 'test-bundle', + 'price' => '', + 'sku_type' => '0', + 'price_type' => Price::PRICE_TYPE_DYNAMIC, + 'weight_type' => '0', + 'shipment_type' => AbstractType::SHIPMENT_TOGETHER, + 'attribute_set_id' => $this->getDefaultAttributeSetId(), + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/FixedBundleProductTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/FixedBundleProductTest.php new file mode 100644 index 0000000000000..908a96368992d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Controller/Adminhtml/Product/FixedBundleProductTest.php @@ -0,0 +1,226 @@ +prepareRequestData($post); + $this->dispatch('backend/catalog/product/save'); + $this->assertBundleOptions($post['bundle_options']); + } + + /** + * @return array + */ + public function fixedBundleProductDataProvider(): array + { + return [ + 'with_dropdown_option' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'select', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + ], + ], + ], + ], + ], + ], + 'with_radio_buttons_option' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'radio', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + ], + ], + ], + ], + ], + ], + 'with_checkbox_option' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'checkbox', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + ], + ], + ], + ], + ], + ], + 'with_multiselect_option' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'multi', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + ], + ], + ], + ], + ], + ], + ]; + } + + /** + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_duplicated.php + * + * @dataProvider multiOptionsDataProvider + * + * @param array $post + * @return void + */ + public function testBundleProductSaveMultiOptions(array $post): void + { + $post = $this->prepareRequestData($post); + $this->dispatch('backend/catalog/product/save'); + $this->assertBundleOptions($post['bundle_options']); + } + + /** + * @return array + */ + public function multiOptionsDataProvider(): array + { + return [ + 'with_two_options_few_selections' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'select', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + [ + 'name' => 'Simple Product', + 'sku' => 'simple-1', + ], + ], + ], + [ + 'type' => 'checkbox', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product', + 'sku' => 'simple-1', + ], + ], + ], + ], + ], + ], + ], + ]; + } + + /** + * @magentoDataFixture Magento/Bundle/_files/bundle_product_checkbox_options.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @dataProvider updateProductDataProvider + * + * @param array $post + * @return void + */ + public function testUpdateProduct(array $post): void + { + $id = $this->productRepository->get('bundle-product-checkbox-options')->getId(); + $post = $this->prepareRequestData($post, (int)$id); + $this->dispatch('backend/catalog/product/save'); + $this->assertBundleOptions($post['bundle_options']); + } + + /** + * @return array + */ + public function updateProductDataProvider(): array + { + return [ + 'update_existing_product' => [ + 'post' => [ + 'bundle_options' => [ + 'bundle_options' => [ + [ + 'type' => 'multi', + 'bundle_selections' => [ + [ + 'name' => 'Simple Product2', + 'sku' => 'simple2', + ], + ], + ], + ], + ], + ], + ], + ]; + } + + /** + * @inheritdoc + */ + protected function getStaticProductData(): array + { + return [ + 'sku' => 'bundle-test-product', + 'name' => 'test-bundle', + 'price' => '150', + 'sku_type' => '1', + 'price_type' => Price::PRICE_TYPE_FIXED, + 'weight_type' => '1', + 'shipment_type' => AbstractType::SHIPMENT_TOGETHER, + 'attribute_set_id' => $this->getDefaultAttributeSetId(), + ]; + } +} From 04ec5edcedb30b9a74e6811c7fcb478265817e7a Mon Sep 17 00:00:00 2001 From: Yurii Sapiha Date: Mon, 16 Mar 2020 15:50:53 +0200 Subject: [PATCH 7/8] MC-32136: Email product to friend --- .../SendFriend/Model/DeleteLogRowsByIp.php | 40 +++ .../SendFriend/Block/ProductViewTest.php | 104 ++++++++ .../Magento/SendFriend/Block/SendTest.php | 124 +++++++--- .../SendFriend/Controller/SendTest.php | 161 +++++++++++++ .../SendFriend/Controller/SendmailTest.php | 190 ++++++++------- .../SendFriend/Model/SendFriendTest.php | 227 ++++++++++++++++++ ...sendfriend_log_record_half_hour_before.php | 20 ++ ...d_log_record_half_hour_before_rollback.php | 13 + 8 files changed, 767 insertions(+), 112 deletions(-) create mode 100644 dev/tests/integration/framework/Magento/TestFramework/SendFriend/Model/DeleteLogRowsByIp.php create mode 100644 dev/tests/integration/testsuite/Magento/SendFriend/Block/ProductViewTest.php create mode 100644 dev/tests/integration/testsuite/Magento/SendFriend/Controller/SendTest.php create mode 100644 dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php create mode 100644 dev/tests/integration/testsuite/Magento/SendFriend/_files/sendfriend_log_record_half_hour_before.php create mode 100644 dev/tests/integration/testsuite/Magento/SendFriend/_files/sendfriend_log_record_half_hour_before_rollback.php diff --git a/dev/tests/integration/framework/Magento/TestFramework/SendFriend/Model/DeleteLogRowsByIp.php b/dev/tests/integration/framework/Magento/TestFramework/SendFriend/Model/DeleteLogRowsByIp.php new file mode 100644 index 0000000000000..aecf40b575957 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/SendFriend/Model/DeleteLogRowsByIp.php @@ -0,0 +1,40 @@ +sendFriendResource = $sendFriendResource; + } + + /** + * Delete rows from sendfriend_log table by ip address + * + * @param string $ipAddress + * @return void + */ + public function execute(string $ipAddress): void + { + $connection = $this->sendFriendResource->getConnection(); + $condition = $connection->quoteInto('ip = ?', ip2long($ipAddress)); + $connection->delete($this->sendFriendResource->getMainTable(), $condition); + } +} diff --git a/dev/tests/integration/testsuite/Magento/SendFriend/Block/ProductViewTest.php b/dev/tests/integration/testsuite/Magento/SendFriend/Block/ProductViewTest.php new file mode 100644 index 0000000000000..daa7b0bab84e3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SendFriend/Block/ProductViewTest.php @@ -0,0 +1,104 @@ +objectManager = Bootstrap::getObjectManager(); + $this->layout = $this->objectManager->get(LayoutInterface::class); + $this->block = $this->layout->createBlock(View::class); + $this->block->setTemplate('Magento_Catalog::product/view/mailto.phtml'); + $this->registry = $this->objectManager->get(Registry::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + parent::tearDown(); + + $this->registry->unregister('product'); + } + + /** + * @return void + */ + public function testSendFriendLinkDisabled(): void + { + $this->registerProduct('simple2'); + $this->assertEmpty($this->block->toHtml()); + } + + /** + * @magentoConfigFixture current_store sendfriend/email/enabled 1 + * + * @return void + */ + public function testSendFriendLinkEnabled(): void + { + $product = $this->registerProduct('simple2'); + $html = $this->block->toHtml(); + $this->assertContains('sendfriend/product/send/id/' . $product->getId(), $html); + $this->assertEquals('Email', trim(strip_tags($html))); + } + + /** + * Register product by sku + * + * @param string $sku + * @return ProductInterface + */ + private function registerProduct(string $sku): ProductInterface + { + $product = $this->productRepository->get($sku); + $this->registry->unregister('product'); + $this->registry->register('product', $product); + + return $product; + } +} diff --git a/dev/tests/integration/testsuite/Magento/SendFriend/Block/SendTest.php b/dev/tests/integration/testsuite/Magento/SendFriend/Block/SendTest.php index 1c6bfe29f876d..539293480d5bb 100644 --- a/dev/tests/integration/testsuite/Magento/SendFriend/Block/SendTest.php +++ b/dev/tests/integration/testsuite/Magento/SendFriend/Block/SendTest.php @@ -3,40 +3,94 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\SendFriend\Block; +use Magento\Customer\Api\AccountManagementInterface; +use Magento\Customer\Model\Session; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\View\LayoutInterface; use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Xpath; +use PHPUnit\Framework\TestCase; -class SendTest extends \PHPUnit\Framework\TestCase +/** + * Class checks send friend email block + * + * @see \Magento\SendFriend\Block\Send + * + * @magentoAppArea frontend + */ +class SendTest extends TestCase { + /** @var array */ + private $elementsXpath = [ + 'sender name field' => "//input[@name='sender[name]']", + 'sender email field' => "//input[@name='sender[email]']", + 'sender message field' => "//textarea[@name='sender[message]']", + 'recipient name field' => "//input[contains(@name, 'recipients[name]')]", + 'recipient email field' => "//input[contains(@name, 'recipients[email]')]", + 'submit button' => "//button[@type='submit']/span[contains(text(), 'Send Email')]", + 'notice massage' => "//div[@id='max-recipient-message']" + . "/span[contains(text(), 'Maximum 1 email addresses allowed.')]" + ]; + + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var LayoutInterface */ + private $layout; + + /** @var Send */ + private $block; + + /** @var Session */ + private $session; + + /** @var AccountManagementInterface */ + private $accountManagement; + /** - * @var \Magento\SendFriend\Block\Send + * @inheritdoc */ - protected $_block; - protected function setUp() { - $this->_block = Bootstrap::getObjectManager()->create(\Magento\SendFriend\Block\Send::class); + $this->objectManager = Bootstrap::getObjectManager(); + $this->layout = $this->objectManager->get(LayoutInterface::class); + $this->block = $this->layout->createBlock(Send::class); + $this->session = $this->objectManager->get(Session::class); + $this->accountManagement = $this->objectManager->get(AccountManagementInterface::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + parent::tearDown(); + + $this->session->logout(); } /** + * @dataProvider formDataProvider + * * @param string $field * @param string $value - * @dataProvider formDataProvider - * @covers \Magento\SendFriend\Block\Send::getUserName - * @covers \Magento\SendFriend\Block\Send::getEmail + * @return void */ - public function testGetCustomerFieldFromFormData($field, $value) + public function testGetCustomerFieldFromFormData(string $field, string $value): void { $formData = ['sender' => [$field => $value]]; - $this->_block->setFormData($formData); + $this->block->setFormData($formData); $this->assertEquals(trim($value), $this->_callBlockMethod($field)); } /** * @return array */ - public function formDataProvider() + public function formDataProvider(): array { return [ ['name', 'Customer Form Name'], @@ -45,29 +99,27 @@ public function formDataProvider() } /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * + * @dataProvider customerSessionDataProvider + * + * @magentoAppIsolation enabled + * * @param string $field * @param string $value - * @dataProvider customerSessionDataProvider - * @covers \Magento\SendFriend\Block\Send::getUserName - * @covers \Magento\SendFriend\Block\Send::getEmail - * @magentoDataFixture Magento/Customer/_files/customer.php + * @return void */ - public function testGetCustomerFieldFromSession($field, $value) + public function testGetCustomerFieldFromSession(string $field, string $value): void { - $logger = $this->createMock(\Psr\Log\LoggerInterface::class); - /** @var $session \Magento\Customer\Model\Session */ - $session = Bootstrap::getObjectManager()->create(\Magento\Customer\Model\Session::class, [$logger]); - /** @var \Magento\Customer\Api\AccountManagementInterface $service */ - $service = Bootstrap::getObjectManager()->create(\Magento\Customer\Api\AccountManagementInterface::class); - $customer = $service->authenticate('customer@example.com', 'password'); - $session->setCustomerDataAsLoggedIn($customer); + $customer = $this->accountManagement->authenticate('customer@example.com', 'password'); + $this->session->setCustomerDataAsLoggedIn($customer); $this->assertEquals($value, $this->_callBlockMethod($field)); } /** * @return array */ - public function customerSessionDataProvider() + public function customerSessionDataProvider(): array { return [ ['name', 'John Smith'], @@ -75,19 +127,37 @@ public function customerSessionDataProvider() ]; } + /** + * @magentoConfigFixture current_store sendfriend/email/max_recipients 1 + * + * @return void + */ + public function testBlockAppearance(): void + { + $this->block->setTemplate('Magento_SendFriend::send.phtml'); + $html = preg_replace('##i', '', $this->block->toHtml()); + foreach ($this->elementsXpath as $key => $xpath) { + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath($xpath, $html), + sprintf('The %s field is not found on the page', $key) + ); + } + } + /** * Call block method based on form field * * @param string $field * @return null|string */ - protected function _callBlockMethod($field) + protected function _callBlockMethod(string $field): ?string { switch ($field) { case 'name': - return $this->_block->getUserName(); + return $this->block->getUserName(); case 'email': - return $this->_block->getEmail(); + return $this->block->getEmail(); default: return null; } diff --git a/dev/tests/integration/testsuite/Magento/SendFriend/Controller/SendTest.php b/dev/tests/integration/testsuite/Magento/SendFriend/Controller/SendTest.php new file mode 100644 index 0000000000000..eccf4ee4c5ef9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SendFriend/Controller/SendTest.php @@ -0,0 +1,161 @@ +customerSession = $this->_objectManager->get(Session::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + parent::tearDown(); + + $this->customerSession->logout(); + } + + /** + * @magentoConfigFixture current_store sendfriend/email/enabled 0 + * + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @return void + */ + public function testSendMailNotAllowed(): void + { + $this->dispatchWithProductIdParam(6); + $this->assert404NotFound(); + } + + /** + * @magentoConfigFixture current_store sendfriend/email/enabled 1 + * @magentoConfigFixture current_store sendfriend/email/allow_guest 0 + * + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @return void + */ + public function testGuestSendMailNotAllowed(): void + { + $this->dispatchWithProductIdParam(6); + $this->assertRedirect($this->stringContains('customer/account/login')); + } + + /** + * @magentoConfigFixture current_store sendfriend/email/enabled 1 + * @magentoConfigFixture current_store sendfriend/email/allow_guest 1 + * + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @return void + */ + public function testGuestSendMailAllowed(): void + { + $this->dispatchWithProductIdParam(6); + $this->assertEquals(Response::STATUS_CODE_200, $this->getResponse()->getHttpResponseCode()); + } + + /** + * @magentoConfigFixture current_store sendfriend/email/enabled 1 + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @return void + */ + public function testLoggedInCustomer(): void + { + $this->customerSession->loginById(1); + $this->dispatchWithProductIdParam(6); + $this->assertEquals(Response::STATUS_CODE_200, $this->getResponse()->getHttpResponseCode()); + } + + /** + * @magentoConfigFixture current_store sendfriend/email/enabled 1 + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * + * @return void + */ + public function testWithoutProductId(): void + { + $this->customerSession->loginById(1); + $this->dispatch('sendfriend/product/send/'); + $this->assert404NotFound(); + } + + /** + * @magentoConfigFixture current_store sendfriend/email/enabled 1 + * @magentoConfigFixture current_store sendfriend/email/max_per_hour 1 + * + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @return void + */ + public function testToMachSendRequests(): void + { + $this->createSendFriendMock(); + $this->customerSession->loginById(1); + $this->dispatchWithProductIdParam(6); + $this->assertSessionMessages( + $this->equalTo([(string)__('You can\'t send messages more than 5 times an hour.')]) + ); + $this->assertEquals(Response::STATUS_CODE_200, $this->getResponse()->getHttpResponseCode()); + } + + /** + * Set product id parameter and dispatch controller + * + * @param int $productId + * @return void + */ + private function dispatchWithProductIdParam(int $productId): void + { + $this->getRequest()->setParam('id', $productId); + $this->dispatch('sendfriend/product/send/'); + } + + /** + * Create mock to imitate to mach send requests + * + * @return void + */ + private function createSendFriendMock(): void + { + $mock = $this->createMock(SendFriend::class); + $mock->method('isExceedLimit')->willReturn(true); + $mock->method('getMaxSendsToFriend')->willReturn(5); + $this->_objectManager->addSharedInstance($mock, SendFriend::class); + } +} diff --git a/dev/tests/integration/testsuite/Magento/SendFriend/Controller/SendmailTest.php b/dev/tests/integration/testsuite/Magento/SendFriend/Controller/SendmailTest.php index 1d6adf52466d2..850225bcee1b2 100644 --- a/dev/tests/integration/testsuite/Magento/SendFriend/Controller/SendmailTest.php +++ b/dev/tests/integration/testsuite/Magento/SendFriend/Controller/SendmailTest.php @@ -10,79 +10,128 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Customer\Model\Session; -use Magento\Framework\Data\Form\FormKey; -use Magento\TestFramework\Helper\Bootstrap; use Magento\Framework\Message\MessageInterface; +use Magento\TestFramework\Helper\Xpath; +use Magento\TestFramework\Mail\Template\TransportBuilderMock; use Magento\TestFramework\Request; use Magento\TestFramework\TestCase\AbstractController; /** - * Class SendmailTest + * Class checks send mail action + * + * @see \Magento\SendFriend\Controller\Product\Sendmail + * + * @magentoAppArea frontend + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled */ class SendmailTest extends AbstractController { + private const MESSAGE_PRODUCT_LINK_XPATH = "//a[contains(@href, '%s') and contains(text(), '%s')]"; + + /** @var Session */ + private $session; + + /** @var ProductRepositoryInterface */ + private $productRepository; + + /** @var TransportBuilderMock */ + private $transportBuilder; + + /** @var array */ + private $staticData = [ + 'sender' => [ + 'name' => 'Test', + 'email' => 'test@example.com', + 'message' => 'Message', + ], + 'recipients' => [ + 'name' => [ + 'Recipient 1', + 'Recipient 2' + ], + 'email' => [ + 'r1@example.com', + 'r2@example.com' + ] + ], + ]; + + /** + * @inheritdoc + */ + protected function setUp() + { + parent::setUp(); + + $this->session = $this->_objectManager->get(Session::class); + $this->productRepository = $this->_objectManager->get(ProductRepositoryInterface::class); + $this->transportBuilder = $this->_objectManager->get(TransportBuilderMock::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + parent::tearDown(); + + $this->session->logout(); + } + /** * Share the product to friend as logged in customer * - * @magentoAppArea frontend - * @magentoDbIsolation enabled - * @magentoAppIsolation enabled * @magentoConfigFixture default_store sendfriend/email/allow_guest 0 * @magentoConfigFixture default_store sendfriend/email/enabled 1 * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoDataFixture Magento/Catalog/_files/products.php + * + * @return void */ - public function testSendActionAsLoggedIn() + public function testSendActionAsLoggedIn(): void { - $product = $this->getProduct(); - $this->login(1); + $product = $this->productRepository->get('custom-design-simple-product'); + $this->session->loginById(1); $this->prepareRequestData(); - $this->dispatch('sendfriend/product/sendmail/id/' . $product->getId()); - $this->assertSessionMessages( - $this->equalTo(['The link to a friend was sent.']), - MessageInterface::TYPE_SUCCESS - ); + $this->checkSuccess($product); } /** * Share the product to friend as guest customer * - * @magentoDbIsolation enabled - * @magentoAppIsolation enabled * @magentoConfigFixture default_store sendfriend/email/enabled 1 * @magentoConfigFixture default_store sendfriend/email/allow_guest 1 * @magentoDataFixture Magento/Catalog/_files/products.php + * + * @return void */ - public function testSendActionAsGuest() + public function testSendActionAsGuest(): void { - $product = $this->getProduct(); + $product = $this->productRepository->get('custom-design-simple-product'); $this->prepareRequestData(); - $this->dispatch('sendfriend/product/sendmail/id/' . $product->getId()); - $this->assertSessionMessages( - $this->equalTo(['The link to a friend was sent.']), - MessageInterface::TYPE_SUCCESS - ); + $this->checkSuccess($product); } /** * Share the product to friend as guest customer with invalid post data * - * @magentoDbIsolation enabled - * @magentoAppIsolation enabled * @magentoConfigFixture default_store sendfriend/email/enabled 1 * @magentoConfigFixture default_store sendfriend/email/allow_guest 1 * @magentoDataFixture Magento/Catalog/_files/products.php + * + * @return void */ - public function testSendActionAsGuestWithInvalidData() + public function testSendActionAsGuestWithInvalidData(): void { - $product = $this->getProduct(); - $this->prepareRequestData(true); - + $product = $this->productRepository->get('custom-design-simple-product'); + unset($this->staticData['sender']['email']); + $this->prepareRequestData(); $this->dispatch('sendfriend/product/sendmail/id/' . $product->getId()); $this->assertSessionMessages( - $this->equalTo(['Invalid Sender Email']), + $this->equalTo([(string)__('Invalid Sender Email')]), MessageInterface::TYPE_ERROR ); } @@ -90,82 +139,53 @@ public function testSendActionAsGuestWithInvalidData() /** * Share the product invisible in catalog to friend as guest customer * - * @magentoDbIsolation enabled - * @magentoAppIsolation enabled * @magentoConfigFixture default_store sendfriend/email/enabled 1 * @magentoConfigFixture default_store sendfriend/email/allow_guest 1 * @magentoDataFixture Magento/Catalog/_files/simple_products_not_visible_individually.php + * + * @return void */ - public function testSendInvisibleProduct() + public function testSendInvisibleProduct(): void { - $product = $this->getInvisibleProduct(); + $product = $this->productRepository->get('simple_not_visible_1'); $this->prepareRequestData(); - $this->dispatch('sendfriend/product/sendmail/id/' . $product->getId()); $this->assert404NotFound(); } /** - * @return ProductInterface - */ - private function getProduct() - { - return $this->_objectManager->get(ProductRepositoryInterface::class)->get('custom-design-simple-product'); - } - - /** - * @return ProductInterface - */ - private function getInvisibleProduct() - { - return $this->_objectManager->get(ProductRepositoryInterface::class)->get('simple_not_visible_1'); - } - - /** - * Login the user + * Check success session message and email content * - * @param string $customerId Customer to mark as logged in for the session + * @param ProductInterface $product * @return void */ - protected function login($customerId) + private function checkSuccess(ProductInterface $product): void { - /** @var Session $session */ - $session = Bootstrap::getObjectManager() - ->get(Session::class); - $session->loginById($customerId); + $this->assertSessionMessages( + $this->equalTo([(string)__('The link to a friend was sent.')]), + MessageInterface::TYPE_SUCCESS + ); + $message = $this->transportBuilder->getSentMessage(); + $this->assertNotNull($message, 'The message was not sent'); + $content = $message->getBody()->getParts()[0]->getRawContent(); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath( + sprintf(self::MESSAGE_PRODUCT_LINK_XPATH, $product->getUrlKey(), $product->getName()), + $content + ), + 'Sent message does not contain product link' + ); } /** - * @param bool $invalidData + * Prepare request before dispatch + * * @return void */ - private function prepareRequestData($invalidData = false) + private function prepareRequestData(): void { - /** @var FormKey $formKey */ - $formKey = $this->_objectManager->get(FormKey::class); - $post = [ - 'sender' => [ - 'name' => 'Test', - 'email' => 'test@example.com', - 'message' => 'Message', - ], - 'recipients' => [ - 'name' => [ - 'Recipient 1', - 'Recipient 2' - ], - 'email' => [ - 'r1@example.com', - 'r2@example.com' - ] - ], - 'form_key' => $formKey->getFormKey(), - ]; - if ($invalidData) { - unset($post['sender']['email']); - } - $this->getRequest()->setMethod(Request::METHOD_POST); - $this->getRequest()->setPostValue($post); + $this->getRequest()->setPostValue($this->staticData); } } diff --git a/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php b/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php new file mode 100644 index 0000000000000..52b2ed05baf9e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php @@ -0,0 +1,227 @@ +objectManager = Bootstrap::getObjectManager(); + $this->sendFriend = $this->objectManager->get(SendFriendFactory::class)->create(); + $this->cookieManager = $this->objectManager->get(CookieManagerInterface::class); + $this->request = $this->objectManager->get(RequestInterface::class); + } + + /** + * @magentoConfigFixture current_store sendfriend/email/max_recipients 1 + * + * @dataProvider validateDataProvider + * + * @param array $sender + * @param array $recipients + * @param string|bool $expectedResult + * @return void + */ + public function testValidate(array $sender, array $recipients, $expectedResult): void + { + $this->prepareData($sender, $recipients); + $this->checkResult($expectedResult, $this->sendFriend->validate()); + } + + /** + * @return array + */ + public function validateDataProvider(): array + { + return [ + 'valid_data' => [ + 'sender' => [ + 'name' => 'Sender Name', + 'email' => 'm1111ytest@mail.com', + 'message' => 'test message', + ], + 'recipients' => [ + 'name' => [ + 'recipient_name', + ], + 'email' => [ + 'recipient_email@example.com', + ], + ], + 'expected_result' => true, + ], + 'empty_message' => [ + 'sender' => [ + 'name' => 'Sender Name', + 'email' => 'm1111ytest@mail.com', + 'message' => '', + ], + 'recipients' => [ + 'name' => [ + 'recipient name', + ], + 'email' => [ + 'recipient_email@example.com', + ], + ], + 'expected_result' => 'Please enter a message.', + ], + 'empty_sender_name' => [ + 'sender' => [ + 'name' => '', + 'email' => 'customer_email@example.com', + 'message' => 'test message', + ], + 'recipients' => [ + 'name' => [ + 'recipient name', + ], + 'email' => [ + 'recipient_email@example.com', + ], + ], + 'expected_result' => 'Please enter a sender name.', + ], + 'empty_recipients' => [ + 'sender' => [ + 'name' => 'Sender Name', + 'email' => 'm1111ytest@mail.com', + 'message' => 'test message', + ], + 'recipients' => [ + 'name' => [], + 'email' => [], + ], + 'expected_result' => 'Please specify at least one recipient.', + ], + 'wrong_recipient_email' => [ + 'sender' => [ + 'name' => 'Sender Name', + 'email' => 'm1111ytest@mail.com', + 'message' => 'test message', + ], + 'recipients' => [ + 'name' => [ + 'recipient name', + ], + 'email' => [ + '123123', + ], + ], + 'expected_result' => 'Please enter a correct recipient email address.', + ], + 'to_much_recipients' => [ + 'sender' => [ + 'name' => 'Sender Name', + 'email' => 'm1111ytest@mail.com', + 'message' => 'test message', + ], + 'recipients' => [ + 'name' => [ + 'recipient name', + 'second name', + ], + 'email' => [ + 'recipient_email@example.com', + 'recipient2_email@example.com', + ], + ], + 'expected_result' => 'No more than 1 emails can be sent at a time.', + ], + ]; + } + + /** + * @magentoConfigFixture current_store sendfriend/email/check_by 0 + * @magentoConfigFixture current_store sendfriend/email/max_per_hour 1 + * + * @return void + */ + public function testisExceedLimitByCookies(): void + { + $this->cookieManager->setPublicCookie(SendFriendHelper::COOKIE_NAME, (string)time()); + $this->assertTrue($this->sendFriend->isExceedLimit()); + } + + /** + * @magentoConfigFixture current_store sendfriend/email/check_by 1 + * @magentoConfigFixture current_store sendfriend/email/max_per_hour 1 + * + * @magentoDataFixture Magento/SendFriend/_files/sendfriend_log_record_half_hour_before.php + * + * @magentoDbIsolation disabled + * @return void + */ + public function testisExceedLimitByIp(): void + { + $this->markTestSkipped('Blocked by MC-31968'); + $parameters = $this->objectManager->create(Parameters::class); + $parameters->set('REMOTE_ADDR', '127.0.0.1'); + $this->request->setServer($parameters); + $this->assertTrue($this->sendFriend->isExceedLimit()); + } + + /** + * Check result + * + * @param array|bool $expectedResult + * @param array|bool $result + * @return void + */ + private function checkResult($expectedResult, $result): void + { + if ($expectedResult === true) { + $this->assertTrue($result); + } else { + $this->assertEquals($expectedResult, (string)reset($result) ?? ''); + } + } + + /** + * Prepare sender and recipient data + * + * @param array $sender + * @param array $recipients + * @return void + */ + private function prepareData(array $sender, array $recipients): void + { + $this->sendFriend->setSender($sender); + $this->sendFriend->setRecipients($recipients); + } +} diff --git a/dev/tests/integration/testsuite/Magento/SendFriend/_files/sendfriend_log_record_half_hour_before.php b/dev/tests/integration/testsuite/Magento/SendFriend/_files/sendfriend_log_record_half_hour_before.php new file mode 100644 index 0000000000000..132cbe97d43ee --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SendFriend/_files/sendfriend_log_record_half_hour_before.php @@ -0,0 +1,20 @@ +get(WebsiteRepositoryInterface::class); +$baseWebsiteId = $websiteRepository->get('base')->getId(); +$ip = ip2long('127.0.0.1'); +$updateDatetime = new \DateTime('-0.5 hours'); +/** @var SendFriendResource $sendFriendResource */ +$sendFriendResource = $objectManager->get(SendFriendResource::class); +$sendFriendResource->addSendItem($ip, $updateDatetime->getTimestamp(), $baseWebsiteId); diff --git a/dev/tests/integration/testsuite/Magento/SendFriend/_files/sendfriend_log_record_half_hour_before_rollback.php b/dev/tests/integration/testsuite/Magento/SendFriend/_files/sendfriend_log_record_half_hour_before_rollback.php new file mode 100644 index 0000000000000..9a700f20bf92c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SendFriend/_files/sendfriend_log_record_half_hour_before_rollback.php @@ -0,0 +1,13 @@ +get(DeleteLogRowsByIp::class); +$deleteLogRowsByIp->execute('127.0.0.1'); From dc27742d408aa144c85b8ef49318113228c43f1c Mon Sep 17 00:00:00 2001 From: Yurii Sapiha Date: Mon, 16 Mar 2020 17:15:43 +0200 Subject: [PATCH 8/8] MC-32136: Email product to friend --- .../testsuite/Magento/SendFriend/Model/SendFriendTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php b/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php index 52b2ed05baf9e..9a9ef6440261a 100644 --- a/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php +++ b/dev/tests/integration/testsuite/Magento/SendFriend/Model/SendFriendTest.php @@ -7,13 +7,13 @@ namespace Magento\SendFriend\Model; -use Laminas\Stdlib\Parameters; use Magento\Framework\App\RequestInterface; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Stdlib\CookieManagerInterface; use Magento\SendFriend\Helper\Data as SendFriendHelper; use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; +use Zend\Stdlib\Parameters; /** * Class checks send friend model behavior