Skip to content

Commit 030176f

Browse files
committed
MC-31754: Storefront: Subscribe/unsubscribe to email newsletter
1 parent 555a134 commit 030176f

File tree

10 files changed

+671
-165
lines changed

10 files changed

+671
-165
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Customer\Block;
9+
10+
use Magento\Framework\ObjectManagerInterface;
11+
use Magento\Framework\View\LayoutInterface;
12+
use Magento\TestFramework\Helper\Bootstrap;
13+
use Magento\TestFramework\Helper\Xpath;
14+
use PHPUnit\Framework\TestCase;
15+
16+
/**
17+
* Class check newsletter subscription block behavior
18+
*
19+
* @see \Magento\Customer\Block\Newsletter
20+
* @magentoAppArea frontend
21+
* @magentoDbIsolation enabled
22+
*/
23+
class NewsletterTest extends TestCase
24+
{
25+
private const LABEL_XPATH = "//form[contains(@class, 'form-newsletter-manage')]"
26+
. "//span[contains(text(), 'Subscription option')]";
27+
private const CHECKBOX_XPATH = "//form[contains(@class, 'form-newsletter-manage')]"
28+
. "//input[@type='checkbox' and @name='is_subscribed']";
29+
private const CHECKBOX_TITLE_XPATH = "//form[contains(@class, 'form-newsletter-manage')]"
30+
. "//label/span[contains(text(), 'General Subscription')]";
31+
private const SAVE_BUTTON_XPATH = "//form[contains(@class, 'form-newsletter-manage')]"
32+
. "//button[@type='submit']/span[contains(text(), 'Save')]";
33+
34+
/** @var ObjectManagerInterface */
35+
private $objectManager;
36+
37+
/** @var LayoutInterface */
38+
private $layout;
39+
40+
/** @var Newsletter */
41+
private $block;
42+
43+
/**
44+
* @inheritdoc
45+
*/
46+
protected function setUp()
47+
{
48+
parent::setUp();
49+
50+
$this->objectManager = Bootstrap::getObjectManager();
51+
$this->layout = $this->objectManager->get(LayoutInterface::class);
52+
$this->block = $this->layout->createBlock(Newsletter::class);
53+
}
54+
55+
/**
56+
* @return void
57+
*/
58+
public function testSubscriptionCheckbox(): void
59+
{
60+
$html = $this->block->toHtml();
61+
$this->assertEquals(
62+
1,
63+
Xpath::getElementsCountForXpath(self::LABEL_XPATH, $html),
64+
'Subscription label is not present on the page'
65+
);
66+
$this->assertEquals(
67+
1,
68+
Xpath::getElementsCountForXpath(self::CHECKBOX_XPATH, $html),
69+
'Subscription checkbox is not present on the page'
70+
);
71+
$this->assertEquals(
72+
1,
73+
Xpath::getElementsCountForXpath(self::CHECKBOX_TITLE_XPATH, $html),
74+
'Subscription checkbox label is not present on the page'
75+
);
76+
$this->assertEquals(
77+
1,
78+
Xpath::getElementsCountForXpath(self::SAVE_BUTTON_XPATH, $html),
79+
'Subscription save button is not present on the page'
80+
);
81+
}
82+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Customer\Api\AccountManagementInterface;
9+
use Magento\Customer\Api\CustomerMetadataInterface;
10+
use Magento\Customer\Model\Data\CustomerFactory;
11+
use Magento\Customer\Model\GroupManagement;
12+
use Magento\Eav\Model\AttributeRepository;
13+
use Magento\Store\Model\StoreManagerInterface;
14+
use Magento\TestFramework\Helper\Bootstrap;
15+
16+
$objectManager = Bootstrap::getObjectManager();
17+
/** @var AccountManagementInterface $accountManagement */
18+
$accountManagement = $objectManager->get(AccountManagementInterface::class);
19+
$customerFactory = $objectManager->get(CustomerFactory::class);
20+
$customerFactory->create();
21+
/** @var StoreManagerInterface $storeManager */
22+
$storeManager = $objectManager->get(StoreManagerInterface::class);
23+
$website = $storeManager->getWebsite('base');
24+
/** @var GroupManagement $groupManagement */
25+
$groupManagement = $objectManager->get(GroupManagement::class);
26+
$defaultStoreId = $website->getDefaultStore()->getId();
27+
/** @var AttributeRepository $attributeRepository */
28+
$attributeRepository = $objectManager->get(AttributeRepository::class);
29+
$gender = $attributeRepository->get(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, 'gender')
30+
->getSource()->getOptionId('Male');
31+
$customer = $customerFactory->create();
32+
$customer->setWebsiteId($website->getId())
33+
->setEmail('new_customer@example.com')
34+
->setGroupId($groupManagement->getDefaultGroup($defaultStoreId)->getId())
35+
->setStoreId($defaultStoreId)
36+
->setPrefix('Mr.')
37+
->setFirstname('John')
38+
->setMiddlename('A')
39+
->setLastname('Smith')
40+
->setSuffix('Esq.')
41+
->setDefaultBilling(1)
42+
->setDefaultShipping(1)
43+
->setGender($gender);
44+
$accountManagement->createAccount($customer, 'Qwert12345');
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Customer\Api\CustomerRepositoryInterface;
9+
use Magento\Framework\Exception\NoSuchEntityException;
10+
use Magento\Framework\Registry;
11+
use Magento\Store\Api\WebsiteRepositoryInterface;
12+
use Magento\TestFramework\Helper\Bootstrap;
13+
14+
$objectManager = Bootstrap::getObjectManager();
15+
/** @var Registry $registry */
16+
$registry = $objectManager->get(Registry::class);
17+
/** @var CustomerRepositoryInterface $customerRepository */
18+
$customerRepository = $objectManager->get(CustomerRepositoryInterface::class);
19+
/** @var WebsiteRepositoryInterface $websiteRepository */
20+
$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class);
21+
$websiteId = $websiteRepository->get('base')->getId();
22+
$registry->unregister('isSecureArea');
23+
$registry->register('isSecureArea', true);
24+
25+
try {
26+
$customer = $customerRepository->get('new_customer@example.com', $websiteId);
27+
$customerRepository->delete($customer);
28+
} catch (NoSuchEntityException $e) {
29+
//customer already deleted
30+
}
31+
32+
$registry->unregister('isSecureArea');
33+
$registry->register('isSecureArea', false);
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Newsletter\Block\Account;
9+
10+
use Magento\Framework\ObjectManagerInterface;
11+
use Magento\Framework\View\Result\Page;
12+
use Magento\TestFramework\Helper\Bootstrap;
13+
use PHPUnit\Framework\TestCase;
14+
15+
/**
16+
* Checks Newsletter Subscriptions link displaying in account dashboard
17+
*
18+
* @magentoAppArea frontend
19+
* @magentoDbIsolation enabled
20+
* @magentoAppIsolation enabled
21+
*/
22+
class LinkTest extends TestCase
23+
{
24+
/** @var ObjectManagerInterface */
25+
private $objectManager;
26+
27+
/** @var Page */
28+
private $page;
29+
30+
/**
31+
* @inheritdoc
32+
*/
33+
protected function setUp()
34+
{
35+
parent::setUp();
36+
37+
$this->objectManager = Bootstrap::getObjectManager();
38+
$this->page = $this->objectManager->create(Page::class);
39+
}
40+
41+
/**
42+
* @return void
43+
*/
44+
public function testNewsletterLink(): void
45+
{
46+
$this->preparePage();
47+
$block = $this->page->getLayout()->getBlock('customer-account-navigation-newsletter-subscriptions-link');
48+
$this->assertNotFalse($block);
49+
$html = $block->toHtml();
50+
$this->assertContains('newsletter/manage/', $html);
51+
$this->assertEquals('Newsletter Subscriptions', strip_tags($html));
52+
}
53+
54+
/**
55+
* @magentoConfigFixture current_store newsletter/general/active 0
56+
*
57+
* @return void
58+
*/
59+
public function testNewsletterLinkDisabled(): void
60+
{
61+
$this->preparePage();
62+
$block = $this->page->getLayout()->getBlock('customer-account-navigation-newsletter-subscriptions-link');
63+
$this->assertFalse($block);
64+
}
65+
66+
/**
67+
* Prepare page before render
68+
*
69+
* @return void
70+
*/
71+
private function preparePage(): void
72+
{
73+
$this->page->addHandle([
74+
'default',
75+
'customer_account',
76+
]);
77+
$this->page->getLayout()->generateXml();
78+
}
79+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Newsletter\Controller\Manage;
9+
10+
use Magento\Customer\Api\CustomerRepositoryInterface;
11+
use Magento\Customer\Model\CustomerRegistry;
12+
use Magento\Customer\Model\Session;
13+
use Magento\Framework\Data\Form\FormKey;
14+
use Magento\Framework\Message\MessageInterface;
15+
use Magento\Newsletter\Model\Plugin\CustomerPlugin;
16+
use Magento\TestFramework\TestCase\AbstractController;
17+
18+
/**
19+
* Class checks customer subscription
20+
*
21+
* @magentoDbIsolation enabled
22+
*/
23+
class SaveTest extends AbstractController
24+
{
25+
/** @var Session */
26+
protected $customerSession;
27+
28+
/** @var CustomerRepositoryInterface */
29+
private $customerRepository;
30+
31+
/** @var FormKey */
32+
private $formKey;
33+
34+
/** @var CustomerRegistry */
35+
private $customerRegistry;
36+
37+
/**
38+
* @inheritdoc
39+
*/
40+
protected function setUp()
41+
{
42+
parent::setUp();
43+
44+
$this->customerSession = $this->_objectManager->get(Session::class);
45+
$this->customerRepository = $this->_objectManager->get(CustomerRepositoryInterface::class);
46+
$this->formKey = $this->_objectManager->get(FormKey::class);
47+
$this->customerRegistry = $this->_objectManager->get(CustomerRegistry::class);
48+
}
49+
50+
/**
51+
* @inheritdoc
52+
*/
53+
protected function tearDown()
54+
{
55+
$this->customerSession->logout();
56+
57+
parent::tearDown();
58+
}
59+
60+
/**
61+
* @magentoDataFixture Magento/Customer/_files/new_customer.php
62+
*
63+
* @dataProvider subscriptionDataProvider
64+
*
65+
* @param bool $isSubscribed
66+
* @param string $expectedMessage
67+
* @return void
68+
*/
69+
public function testSaveAction(bool $isSubscribed, string $expectedMessage): void
70+
{
71+
$this->loginCustomer('new_customer@example.com');
72+
$this->_objectManager->removeSharedInstance(CustomerPlugin::class);
73+
$this->dispatchSaveAction($isSubscribed);
74+
$this->assertSuccessSubscription($expectedMessage);
75+
}
76+
77+
/**
78+
* @return array
79+
*/
80+
public function subscriptionDataProvider(): array
81+
{
82+
return [
83+
'subscribe_customer' => [
84+
'is_subscribed' => true,
85+
'expected_message' => 'We have saved your subscription.',
86+
],
87+
'unsubscribe_customer' => [
88+
'is_subscribed' => false,
89+
'expected_message' => 'We have updated your subscription.',
90+
],
91+
];
92+
}
93+
94+
/**
95+
* @magentoDataFixture Magento/Customer/_files/customer_confirmation_config_enable.php
96+
* @magentoDataFixture Magento/Customer/_files/new_customer.php
97+
*
98+
* @return void
99+
*/
100+
public function testSubscribeWithEnabledConfirmation(): void
101+
{
102+
$this->loginCustomer('new_customer@example.com');
103+
$this->dispatchSaveAction(true);
104+
$this->assertSuccessSubscription('A confirmation request has been sent.');
105+
}
106+
107+
/**
108+
* @magentoDataFixture Magento/Newsletter/_files/customer_with_subscription.php
109+
*
110+
* @return void
111+
*/
112+
public function testUnsubscribeSubscribedCustomer(): void
113+
{
114+
$this->loginCustomer('new_customer@example.com');
115+
$this->_objectManager->removeSharedInstance(CustomerPlugin::class);
116+
$this->dispatchSaveAction(false);
117+
$this->assertSuccessSubscription('We have removed your newsletter subscription.');
118+
}
119+
120+
/**
121+
* Dispatch save action with parameters
122+
*
123+
* @param string $isSubscribed
124+
* @return void
125+
*/
126+
private function dispatchSaveAction(bool $isSubscribed): void
127+
{
128+
$this->_objectManager->removeSharedInstance(CustomerPlugin::class);
129+
$this->getRequest()->setParam('form_key', $this->formKey->getFormKey())
130+
->setParam('is_subscribed', $isSubscribed);
131+
$this->dispatch('newsletter/manage/save');
132+
}
133+
134+
/**
135+
* Login customer by email
136+
*
137+
* @param string $email
138+
* @return void
139+
*/
140+
private function loginCustomer(string $email): void
141+
{
142+
$customer = $this->customerRepository->get($email);
143+
$this->customerSession->loginById($customer->getId());
144+
}
145+
146+
/**
147+
* Assert that action was successfully done
148+
*
149+
* @param string $expectedMessage
150+
* @return void
151+
*/
152+
private function assertSuccessSubscription(string $expectedMessage): void
153+
{
154+
$this->assertRedirect($this->stringContains('customer/account/'));
155+
$this->assertSessionMessages($this->equalTo([(string)__($expectedMessage)]), MessageInterface::TYPE_SUCCESS);
156+
}
157+
}

0 commit comments

Comments
 (0)