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/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/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(),
+ ];
+ }
+}
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..f532e2fcb7182
--- /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->stringContains($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->stringContains($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->stringContains(
+ $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->stringContains($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->stringContains($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->stringContains($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($this->baseControllerUrl . '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 1442449f6aedd..e2ba275a5a438 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
@@ -6,44 +6,32 @@
namespace Magento\Customer\Controller\Adminhtml;
-use Magento\Customer\Api\AccountManagementInterface;
-use Magento\Customer\Api\AddressRepositoryInterface;
+use Magento\Backend\Model\Session;
+use Magento\Customer\Api\CustomerNameGenerationInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
-use Magento\Customer\Controller\RegistryConstants;
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
*
* @var string
*/
- protected $_baseControllerUrl;
+ private $baseControllerUrl = 'backend/customer/index/';
/** @var CustomerRepositoryInterface */
- protected $customerRepository;
+ private $customerRepository;
- /** @var AddressRepositoryInterface */
- protected $addressRepository;
-
- /** @var AccountManagementInterface */
- protected $accountManagement;
-
- /** @var \Magento\Framework\Data\Form\FormKey */
- protected $formKey;
-
- /**@var \Magento\Customer\Helper\View */
- protected $customerViewHelper;
-
- /** @var \Magento\TestFramework\ObjectManager */
- protected $objectManager;
+ /** @var CustomerNameGenerationInterface */
+ private $customerViewHelper;
/**
* @inheritDoc
@@ -51,24 +39,8 @@ class IndexTest extends \Magento\TestFramework\TestCase\AbstractBackendControlle
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(CustomerNameGenerationInterface::class);
}
/**
@@ -79,144 +51,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 +105,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 +153,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 +164,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
*/
@@ -502,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));
}
/**
@@ -514,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));
}
/**
@@ -529,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'));
}
/**
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/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/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..4ff16189df1ba 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);
}
/**
@@ -387,73 +361,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
*/
@@ -620,310 +527,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
*/
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/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('#