From eebd793e62194409c43c93ee920743046c40a65a Mon Sep 17 00:00:00 2001 From: Stefan Hagspiel Date: Thu, 3 Jan 2019 18:41:06 +0100 Subject: [PATCH] #73: add register / login / logout functional tests --- .../PostConfirmationListener.php | 2 +- .../EventListener/UserChangeListener.php | 19 +- src/MembersBundle/Manager/UserManager.php | 1 - .../Resources/config/services/event.yml | 2 + tests/_support/Helper/MembersFrontend.php | 159 +++++++++++++++++ tests/_support/Helper/PimcoreBackend.php | 7 +- tests/_support/Test/DachcomBundleTestCase.php | 2 +- tests/_support/Util/MembersHelper.php | 18 +- tests/bundle_tests/functional.suite.dist.yml | 4 +- .../functional/Frontend/LoginLogoutCest.php | 82 +++++++++ .../functional/Frontend/RegisterCest.php | 162 ++++++++++++++++++ .../symfony/config_reg_confirm_by_admin.yml | 2 + ...reg_confirm_by_admin_with_admin_notify.yml | 3 + ..._confirm_by_admin_with_after_confirmed.yml | 3 + .../symfony/config_reg_confirm_instant.yml | 2 + 15 files changed, 437 insertions(+), 31 deletions(-) create mode 100644 tests/_support/Helper/MembersFrontend.php create mode 100644 tests/bundle_tests/functional/Frontend/LoginLogoutCest.php create mode 100644 tests/bundle_tests/functional/Frontend/RegisterCest.php create mode 100755 tests/etc/config/bundle/symfony/config_reg_confirm_by_admin.yml create mode 100755 tests/etc/config/bundle/symfony/config_reg_confirm_by_admin_with_admin_notify.yml create mode 100755 tests/etc/config/bundle/symfony/config_reg_confirm_by_admin_with_after_confirmed.yml create mode 100755 tests/etc/config/bundle/symfony/config_reg_confirm_instant.yml diff --git a/src/MembersBundle/EventListener/PostConfirmationListener.php b/src/MembersBundle/EventListener/PostConfirmationListener.php index 7d21ff1d..21ab0161 100755 --- a/src/MembersBundle/EventListener/PostConfirmationListener.php +++ b/src/MembersBundle/EventListener/PostConfirmationListener.php @@ -61,7 +61,7 @@ public function __construct( UrlGeneratorInterface $router, SessionInterface $session, TokenGenerator $tokenGenerator, - $postEventType + string $postEventType ) { $this->userManager = $userManager; $this->mailer = $pimcoreMailer; diff --git a/src/MembersBundle/EventListener/UserChangeListener.php b/src/MembersBundle/EventListener/UserChangeListener.php index f653c4b4..2350ac50 100644 --- a/src/MembersBundle/EventListener/UserChangeListener.php +++ b/src/MembersBundle/EventListener/UserChangeListener.php @@ -3,7 +3,6 @@ namespace MembersBundle\EventListener; use MembersBundle\Adapter\User\UserInterface; -use MembersBundle\Configuration\Configuration; use MembersBundle\Mailer\Mailer; use MembersBundle\Manager\UserManagerInterface; use Pimcore\Event\DataObjectEvents; @@ -23,22 +22,25 @@ class UserChangeListener implements EventSubscriberInterface protected $mailer; /** - * @var Configuration + * @var string */ - protected $configuration; + protected $postEventType; /** * UserChangeListener constructor. * * @param UserManagerInterface $userManager * @param Mailer $pimcoreMailer - * @param Configuration $configuration + * @param string $postEventType */ - public function __construct(UserManagerInterface $userManager, Mailer $pimcoreMailer, Configuration $configuration) - { + public function __construct( + UserManagerInterface $userManager, + Mailer $pimcoreMailer, + string $postEventType + ) { $this->userManager = $userManager; $this->mailer = $pimcoreMailer; - $this->configuration = $configuration; + $this->postEventType = $postEventType; } /** @@ -58,8 +60,7 @@ public function handleObjectUpdate(DataObjectEvent $e) { $user = $e->getObject(); - if (!$user instanceof UserInterface - || $this->configuration->getConfig('post_register_type') !== 'confirm_by_admin') { + if (!$user instanceof UserInterface || $this->postEventType !== 'confirm_by_admin') { return; } diff --git a/src/MembersBundle/Manager/UserManager.php b/src/MembersBundle/Manager/UserManager.php index 9ecccd44..0a4b5262 100644 --- a/src/MembersBundle/Manager/UserManager.php +++ b/src/MembersBundle/Manager/UserManager.php @@ -221,7 +221,6 @@ private function setupNewUser(UserInterface $user) } $objects = $listing->getObjects(); - if (count($objects) > 0) { $userGroups[] = $objects[0]; } diff --git a/src/MembersBundle/Resources/config/services/event.yml b/src/MembersBundle/Resources/config/services/event.yml index 11838ff4..8d76e70b 100644 --- a/src/MembersBundle/Resources/config/services/event.yml +++ b/src/MembersBundle/Resources/config/services/event.yml @@ -56,6 +56,8 @@ services: # event: listen to changes on user updates. send mails if available. MembersBundle\EventListener\UserChangeListener: + arguments: + $postEventType: '%members.registration.event.type%' tags: - { name: kernel.event_subscriber } diff --git a/tests/_support/Helper/MembersFrontend.php b/tests/_support/Helper/MembersFrontend.php new file mode 100644 index 00000000..25802c8c --- /dev/null +++ b/tests/_support/Helper/MembersFrontend.php @@ -0,0 +1,159 @@ + 'MembersFrontend needs the PimcoreBackend module to work.']; + } + + /** + * @param PimcoreBackend $connection + */ + public function _inject(PimcoreBackend $connection) + { + $this->pimcoreBackend = $connection; + } + + public function haveARegisteredFrontEndUser($published = false) + { + $userManager = $this->getContainer()->get(UserManager::class); + $configuration = $this->getContainer()->get(Configuration::class); + + $membersStoreObject = DataObject::getByPath($configuration->getConfig('storage_path')); + + $userObject = $userManager->createUser(); + $userObject->setParent($membersStoreObject); + $userObject->setEmail('test@universe.org'); + $userObject->setUserName('chuck'); + $userObject->setPlainPassword('test'); + $userObject->setPublished(false); + + $user = $userManager->updateUser($userObject); + + if ($published === true) { + $user->setConfirmationToken(null); + $user->setPublished(true); + $userManager->updateUser($user); + } + + return $user; + } + + public function haveALoggedInFrontEndUser() + { + $tokenStorage = $this->getContainer()->get('security.token_storage'); + + $this->assertNotNull($tokenStorage->getToken()); + $this->assertInstanceOf(UserInterface::class, $tokenStorage->getToken()->getUser()); + } + + public function haveANotLoggedInFrontEndUser() + { + $tokenStorage = $this->getContainer()->get('security.token_storage'); + + $this->assertNotNull($tokenStorage->getToken()); + $this->assertSame('anon.', $tokenStorage->getToken()->getUser()); + } + + /** + * Actor Function to get confirmation link from email + * + * @param Email $email + * + * @return string|null + */ + public function haveConfirmationLinkInEmail(Email $email) + { + $foundEmails = $this->pimcoreBackend->getEmailsFromDocumentIds([$email->getId()]); + $serializer = $this->pimcoreBackend->getSerializer(); + + $propertyKey = 'confirmationUrl'; + $link = null; + foreach ($foundEmails as $email) { + $params = $serializer->decode($email->getParams(), 'json', ['json_decode_associative' => true]); + $key = array_search($propertyKey, array_column($params, 'key')); + if ($key === false) { + $this->fail(sprintf('Failed asserting that mail params array has the key "%s".', $propertyKey)); + } else { + $data = $params[$key]; + $link = $data['data']['value']; + } + break; + } + + $this->assertNotEmpty($link); + + return $link; + + } + + public function seeAUserWithValidToken() + { + $user = $this->grabOneUserAfterRegistration(); + $this->assertNotEmpty($user->getConfirmationToken()); + } + + public function seeAUserWithInvalidatedToken() + { + $user = $this->grabOneUserAfterRegistration(); + $this->assertNull($user->getConfirmationToken()); + } + + public function seeAPublishedUserAfterRegistration() + { + $user = $this->grabOneUserAfterRegistration(); + $this->assertTrue($user->getPublished()); + } + + public function seeAUnpublishedUserAfterRegistration() + { + $user = $this->grabOneUserAfterRegistration(); + $this->assertFalse($user->getPublished()); + } + + /** + * @return UserInterface + * @throws \Exception + */ + public function grabOneUserAfterRegistration() + { + $list = MembersUser::getList(['unpublished' => true]); + $users = $list->load(); + + $this->assertCount(1, $users); + $this->assertInstanceOf(UserInterface::class, $users[0]); + + return $users[0]; + + } + + /** + * @return Container + * @throws \Codeception\Exception\ModuleException + */ + protected function getContainer() + { + return $this->getModule('\\' . PimcoreCore::class)->getContainer(); + } +} diff --git a/tests/_support/Helper/PimcoreBackend.php b/tests/_support/Helper/PimcoreBackend.php index 1912e384..7c5104ae 100644 --- a/tests/_support/Helper/PimcoreBackend.php +++ b/tests/_support/Helper/PimcoreBackend.php @@ -37,7 +37,7 @@ public function _after(TestInterface $test) TestHelper::cleanUp(); FileGeneratorHelper::cleanUp(); MembersHelper::cleanUp(); - MembersHelper::reCreateMembersFolder(); + MembersHelper::reCreateMembersStructure(); parent::_after($test); } @@ -299,7 +299,7 @@ public function seeKeyInFrontendTranslations(string $key) * * @return Log[] */ - protected function getEmailsFromDocumentIds(array $documentIds) + public function getEmailsFromDocumentIds(array $documentIds) { $emailLogs = new Log\Listing(); $emailLogs->addConditionParam(sprintf('documentId IN (%s)', implode(',', $documentIds))); @@ -469,7 +469,6 @@ protected function createMembersArea() sprintf('%s:1.hideWhenLoggedIn', MembersHelper::AREA_TEST_NAMESPACE) => $hideWhenLoggedIn, sprintf('%s:1.showSnippedWhenLoggedIn', MembersHelper::AREA_TEST_NAMESPACE) => $showSnippedWhenLoggedIn, ]; - } /** @@ -484,7 +483,7 @@ protected function getContainer() /** * @return Serializer */ - protected function getSerializer() + public function getSerializer() { $serializer = null; diff --git a/tests/_support/Test/DachcomBundleTestCase.php b/tests/_support/Test/DachcomBundleTestCase.php index 25a153fb..6ae272f9 100644 --- a/tests/_support/Test/DachcomBundleTestCase.php +++ b/tests/_support/Test/DachcomBundleTestCase.php @@ -18,7 +18,7 @@ protected function _after() { TestHelper::cleanUp(); MembersHelper::cleanUp(); - MembersHelper::reCreateMembersFolder(); + MembersHelper::reCreateMembersStructure(); FileGeneratorHelper::cleanUp(); parent::_after(); diff --git a/tests/_support/Util/MembersHelper.php b/tests/_support/Util/MembersHelper.php index 61b2d11e..573054a2 100644 --- a/tests/_support/Util/MembersHelper.php +++ b/tests/_support/Util/MembersHelper.php @@ -2,7 +2,7 @@ namespace DachcomBundle\Test\Util; -use Pimcore\Model\DataObject; +use MembersBundle\Tool\Install; class MembersHelper { @@ -44,19 +44,9 @@ public static function generateEditableConfiguration(string $name, string $type, return $data; } - public static function reCreateMembersFolder() + public static function reCreateMembersStructure() { - //re-create members data folder. - try { - $folder = new DataObject\Folder(); - $folder->setParentId(1); - $folder->setKey('members'); - $folder->setLocked(true); - $folder->save(); - } catch (\Exception $e) { - \Codeception\Util\Debug::debug( - sprintf('[MEMBERS ERROR] error while re-creating members object folder. message was: ' . $e->getMessage()) - ); - } + $installer = \Pimcore::getContainer()->get(Install::class); + $installer->initializeFreshSetup(); } } diff --git a/tests/bundle_tests/functional.suite.dist.yml b/tests/bundle_tests/functional.suite.dist.yml index cfaad12f..e24728e1 100644 --- a/tests/bundle_tests/functional.suite.dist.yml +++ b/tests/bundle_tests/functional.suite.dist.yml @@ -11,4 +11,6 @@ modules: - \DachcomBundle\Test\Helper\PimcoreAdminJson: depends: \DachcomBundle\Test\Helper\PimcoreCore - \DachcomBundle\Test\Helper\PimcoreBackend - - \DachcomBundle\Test\Helper\PimcoreUser \ No newline at end of file + - \DachcomBundle\Test\Helper\PimcoreUser + - \DachcomBundle\Test\Helper\MembersFrontend: + depends: \DachcomBundle\Test\Helper\PimcoreBackend \ No newline at end of file diff --git a/tests/bundle_tests/functional/Frontend/LoginLogoutCest.php b/tests/bundle_tests/functional/Frontend/LoginLogoutCest.php new file mode 100644 index 00000000..6fc7c41b --- /dev/null +++ b/tests/bundle_tests/functional/Frontend/LoginLogoutCest.php @@ -0,0 +1,82 @@ +amOnPage('/en/members/login'); + $I->see('Username', 'form[class="members_user_login"] label'); + $I->seeElement('form[class="members_user_login"] input[type="text"][name="_username"]'); + $I->see('Password', 'form[class="members_user_login"] label'); + $I->seeElement('form[class="members_user_login"] input[type="password"][name="_password"]'); + $I->see('Remember me', 'form[class="members_user_login"] label'); + $I->seeElement('form[class="members_user_login"] input[type="checkbox"][name="_remember_me"]'); + $I->seeElement('form[class="members_user_login"] button[type="submit"][name="_submit"]'); + } + + /** + * @param FunctionalTester $I + */ + public function testLoginWithNonExistingUser(FunctionalTester $I) + { + $this->login($I); + $I->see('invalid credentials.', 'div'); + $I->haveANotLoggedInFrontEndUser(); + } + + /** + * @param FunctionalTester $I + */ + public function testLoginWithInactiveUser(FunctionalTester $I) + { + $I->haveARegisteredFrontEndUser(false); + + $this->login($I); + $I->see('Account is disabled.', 'div'); + $I->haveANotLoggedInFrontEndUser(); + } + + /** + * @param FunctionalTester $I + */ + public function testLoginWithValidUser(FunctionalTester $I) + { + $I->haveARegisteredFrontEndUser(true); + $this->login($I); + $I->haveALoggedInFrontEndUser(true); + } + + /** + * @param FunctionalTester $I + */ + public function testLogout(FunctionalTester $I) + { + $I->haveARegisteredFrontEndUser(true); + $this->login($I); + $I->haveALoggedInFrontEndUser(true); + + $I->amOnPage('/en/members/logout'); + $I->haveANotLoggedInFrontEndUser(true); + } + + /** + * @param FunctionalTester $I + */ + private function login(FunctionalTester $I) + { + $userName = 'chuck'; + $password = 'test'; + + $I->amOnPage('/en/members/login'); + $I->fillField('form[class="members_user_login"] input[type="text"][name="_username"]', $userName); + $I->fillField('form[class="members_user_login"] input[type="password"][name="_password"]', $password); + $I->click('Log In'); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/functional/Frontend/RegisterCest.php b/tests/bundle_tests/functional/Frontend/RegisterCest.php new file mode 100644 index 00000000..d466006c --- /dev/null +++ b/tests/bundle_tests/functional/Frontend/RegisterCest.php @@ -0,0 +1,162 @@ +amOnPage('/en/members/register'); + $I->see('Email', 'form[name="members_user_registration_form"] label'); + $I->seeElement('form[name="members_user_registration_form"] input[type="email"][id="members_user_registration_form_email"]'); + $I->see('Username', 'form[name="members_user_registration_form"] label'); + $I->seeElement('form[name="members_user_registration_form"] input[type="text"][id="members_user_registration_form_username"]'); + $I->see('Password', 'form[name="members_user_registration_form"] label'); + $I->seeElement('form[name="members_user_registration_form"] input[type="password"][id="members_user_registration_form_plainPassword_first"]'); + $I->see('Repeat password', 'form[name="members_user_registration_form"] label'); + $I->seeElement('form[name="members_user_registration_form"] input[type="password"][id="members_user_registration_form_plainPassword_second"]'); + $I->seeElement('form[name="members_user_registration_form"] button[type="submit"][id="members_user_registration_form_submit"]'); + } + + /** + * @param FunctionalTester $I + */ + public function testUserRegistrationFormConfirmByMail(FunctionalTester $I) + { + $email = 'test@universe.org'; + $userName = 'chuck'; + + $this->register($I); + + $I->see('The user has been created successfully.', '.alert.flash-success'); + $I->see(sprintf('An email has been sent to %s. It contains an activation link you must click to activate your account.', $email), 'p'); + + $I->seeAUnpublishedUserAfterRegistration(); + $I->seeAUserWithValidToken(); + + $email = Email::getByPath('/email/register-confirm'); + $I->canSeeEmailIsSent($email); + $I->seePropertyKeysInEmail($email, ['user', 'confirmationUrl']); + + $confirmationLink = $I->haveConfirmationLinkInEmail($email); + $I->amOnPage($confirmationLink); + $I->see(sprintf('Congrats %s, your account is now activated.', $userName), 'p'); + + $I->seeAPublishedUserAfterRegistration(); + $I->seeAUserWithInvalidatedToken(); + + $email = Email::getByPath('/email/register-confirmed'); + $I->seeEmailIsNotSent($email); + } + + /** + * @param FunctionalTester $I + * + * @throws \Exception + */ + public function testUserRegistrationFormConfirmByAdmin(FunctionalTester $I) + { + $I->haveABootedSymfonyConfiguration('config_reg_confirm_by_admin.yml'); + + $this->register($I); + + $I->see('The user has been created successfully.', '.alert.flash-success'); + $I->see('Your account was created successfully and must be activated by site stuff.', 'p'); + + $I->seeAUnpublishedUserAfterRegistration(); + $I->seeAUserWithValidToken(); + + $email = Email::getByPath('/email/register-confirm'); + $I->seeEmailIsNotSent($email); + + $user = $I->grabOneUserAfterRegistration(); + $user->setPublished(true); + $user->save(); + + $email = Email::getByPath('/email/register-confirmed'); + $I->seeEmailIsNotSent($email); + } + + /** + * @param FunctionalTester $I + * + * @throws \Exception + */ + public function testUserRegistrationFormConfirmByAdminWithFinalConfirmationMail(FunctionalTester $I) + { + $I->haveABootedSymfonyConfiguration('config_reg_confirm_by_admin_with_after_confirmed.yml'); + + $this->register($I); + + $user = $I->grabOneUserAfterRegistration(); + $user->setPublished(true); + $user->save(); + + $email = Email::getByPath('/email/register-confirmed'); + $I->canSeeEmailIsSent($email); + $I->seePropertyKeysInEmail($email, ['user', 'loginpage']); + } + + /** + * @param FunctionalTester $I + * + * @throws \Exception + */ + public function testUserRegistrationFormConfirmByAdminWithAdminNotificationMail(FunctionalTester $I) + { + $I->haveABootedSymfonyConfiguration('config_reg_confirm_by_admin_with_admin_notify.yml'); + + $email = Email::getByPath('/email/admin-register-notification'); + $email->setTo('test@universe.org'); + $email->save(); + + $this->register($I); + + $I->canSeeEmailIsSent($email); + $I->seePropertyKeysInEmail($email, ['user', 'deeplink']); + } + + /** + * @param FunctionalTester $I + */ + public function testUserRegistrationFormConfirmInstant(FunctionalTester $I) + { + $I->haveABootedSymfonyConfiguration('config_reg_confirm_instant.yml'); + + $this->register($I); + + $I->see('The user has been created successfully.', '.alert.flash-success'); + $I->see('Congrats chuck, your account is now activated.', 'p'); + + $I->seeAPublishedUserAfterRegistration(); + $I->seeAUserWithInvalidatedToken(); + + $email = Email::getByPath('/email/register-confirm'); + $I->seeEmailIsNotSent($email); + + $email = Email::getByPath('/email/register-confirmed'); + $I->seeEmailIsNotSent($email); + } + + /** + * @param FunctionalTester $I + */ + private function register(FunctionalTester $I) + { + $email = 'test@universe.org'; + $userName = 'chuck'; + + $I->amOnPage('/en/members/register'); + $I->fillField('form[name="members_user_registration_form"] input[type="email"][id="members_user_registration_form_email"]', $email); + $I->fillField('form[name="members_user_registration_form"] input[type="text"][id="members_user_registration_form_username"]', $userName); + $I->fillField('form[name="members_user_registration_form"] input[type="password"][id="members_user_registration_form_plainPassword_first"]', 'password'); + $I->fillField('form[name="members_user_registration_form"] input[type="password"][id="members_user_registration_form_plainPassword_second"]', 'password'); + $I->click('Register'); + } +} \ No newline at end of file diff --git a/tests/etc/config/bundle/symfony/config_reg_confirm_by_admin.yml b/tests/etc/config/bundle/symfony/config_reg_confirm_by_admin.yml new file mode 100755 index 00000000..ceba6b5b --- /dev/null +++ b/tests/etc/config/bundle/symfony/config_reg_confirm_by_admin.yml @@ -0,0 +1,2 @@ +members: + post_register_type: 'confirm_by_admin' diff --git a/tests/etc/config/bundle/symfony/config_reg_confirm_by_admin_with_admin_notify.yml b/tests/etc/config/bundle/symfony/config_reg_confirm_by_admin_with_admin_notify.yml new file mode 100755 index 00000000..18f9929a --- /dev/null +++ b/tests/etc/config/bundle/symfony/config_reg_confirm_by_admin_with_admin_notify.yml @@ -0,0 +1,3 @@ +members: + post_register_type: 'confirm_by_admin' + send_admin_mail_after_register: true diff --git a/tests/etc/config/bundle/symfony/config_reg_confirm_by_admin_with_after_confirmed.yml b/tests/etc/config/bundle/symfony/config_reg_confirm_by_admin_with_after_confirmed.yml new file mode 100755 index 00000000..52f54906 --- /dev/null +++ b/tests/etc/config/bundle/symfony/config_reg_confirm_by_admin_with_after_confirmed.yml @@ -0,0 +1,3 @@ +members: + post_register_type: 'confirm_by_admin' + send_user_mail_after_confirmed: true diff --git a/tests/etc/config/bundle/symfony/config_reg_confirm_instant.yml b/tests/etc/config/bundle/symfony/config_reg_confirm_instant.yml new file mode 100755 index 00000000..964b3ef7 --- /dev/null +++ b/tests/etc/config/bundle/symfony/config_reg_confirm_instant.yml @@ -0,0 +1,2 @@ +members: + post_register_type: 'confirm_instant'