diff --git a/.gitignore b/.gitignore index 7c9f4c84..0139f99d 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,12 @@ Vagrantfile .vagrant php-cgi.core .sass-cache + +# codeception (only stage *.dist.yml config files) +/codeception.yml +/tests/codeception.yml +/tests/*.suite.yml +/tests/_output/* +/tests/_data/* +!/tests/_data/.gitkeep +/tests/_support/_generated/* \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..468cbf59 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,69 @@ +sudo: required +language: php +addons: + chrome: stable + mariadb: '10.1' + +env: + global: + - PIMCORE_ENVIRONMENT=test + - DACHCOM_BUNDLE_TEST=1 + - PIMCORE_TEST_URL=http://localhost + - CHROME_DRIVER_VERSION=2.41 + - SELENIUM_VERSION=3.6.0 + - WEBDRIVER_HOST=localhost + - WEBDRIVER_URL="http://localhost:8080/" + - PIMCORE_TEST_DB_DSN="mysql://root@localhost/dachcom_bundle_test" + - PIMCORE_CLASS_DIRECTORY="${TRAVIS_BUILD_DIR}/lib/Members/tests/_output/var/classes/DataObject" + - SYMFONY_DEPRECATIONS_HELPER=weak +matrix: + include: + # pimcore 5.4.x + - sudo: required + php: 7.1 + env: + - PIMCORE_SKELETON_BRANCH="tags/v1.0.4" + - sudo: required + php: 7.2 + env: + - PIMCORE_SKELETON_BRANCH="tags/v1.0.4" + # pimcore 5.5.x + - sudo: required + php: 7.1 + env: + - PIMCORE_SKELETON_BRANCH="tags/v1.0.5" + - sudo: required + php: 7.2 + env: + - PIMCORE_SKELETON_BRANCH="tags/v1.0.5" + # pimcore 5.6.x + - sudo: required + php: 7.1 + env: + - PIMCORE_SKELETON_BRANCH="tags/v1.1.0" + - sudo: required + php: 7.2 + env: + - PIMCORE_SKELETON_BRANCH="tags/v1.1.0" + fast_finish: true + +cache: + directories: + - $HOME/.composer/cache + +install: +- tests/etc/travis/install + +after_failure: +- cd $TRAVIS_BUILD_DIR +- cat ./lib/Members/tests/_output/* + +script: +- '$HOME/chromedriver --url-base=/wd/hub &' +- 'php ${TRAVIS_BUILD_DIR}/bin/console server:start 127.0.0.1:8080' +- 'php ${TRAVIS_BUILD_DIR}/bin/console server:status' +- etc/travis/script + +notifications: + email: + - shagspiel@dachcom.ch \ No newline at end of file diff --git a/README.md b/README.md index 8f9bcb09..44837392 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Add frontend user authentication and document restriction to pimcore 5.0. [![Software License](https://img.shields.io/badge/license-GPLv3-brightgreen.svg?style=flat-square)](LICENSE.md) [![Latest Release](https://img.shields.io/packagist/v/dachcom-digital/members.svg?style=flat-square)](https://packagist.org/packages/dachcom-digital/members) [![Scrutinizer](https://img.shields.io/scrutinizer/g/dachcom-digital/pimcore-members.svg?style=flat-square)](https://www.scrutinizer-ci.com/g/dachcom-digital/pimcore-members/) +[![Travis](https://img.shields.io/travis/dachcom-digital/pimcore-members/master.svg?style=flat-square)](https://travis-ci.org/dachcom-digital/pimcore-members) ## Requirements * Pimcore 5. diff --git a/codeception.dist.yml b/codeception.dist.yml new file mode 100644 index 00000000..ff60cbf4 --- /dev/null +++ b/codeception.dist.yml @@ -0,0 +1,7 @@ +settings: + memory_limit: -1 + colors: true +paths: + log: var/logs +include: + - tests diff --git a/composer.json b/composer.json index 1cc7afd0..b0d8eefb 100755 --- a/composer.json +++ b/composer.json @@ -28,6 +28,6 @@ } }, "require": { - "pimcore/core-version": "^5.0.0" + "pimcore/core-version": "^5.4.0" } } diff --git a/src/MembersBundle/Command/ClassInstallerCommand.php b/src/MembersBundle/Command/ClassInstallerCommand.php index b9c83dc1..c72ece38 100755 --- a/src/MembersBundle/Command/ClassInstallerCommand.php +++ b/src/MembersBundle/Command/ClassInstallerCommand.php @@ -36,9 +36,10 @@ protected function execute(InputInterface $input, OutputInterface $output) $helper = $this->getHelper('question'); $question = new ConfirmationQuestion('Do you want to install the classes now? (y/n) ', false); - if (!$helper->ask($input, $output, $question)) { + if ($input->isInteractive() === true && !$helper->ask($input, $output, $question)) { return; } + foreach ($this->getClasses() as $className => $path) { $class = new ClassDefinition(); diff --git a/src/MembersBundle/Configuration/Configuration.php b/src/MembersBundle/Configuration/Configuration.php index a73e1122..939c03e1 100644 --- a/src/MembersBundle/Configuration/Configuration.php +++ b/src/MembersBundle/Configuration/Configuration.php @@ -37,14 +37,6 @@ public function setConfig($config = []) $this->config = $config; } - /** - * @return array - */ - public function getConfigNode() - { - return $this->config; - } - /** * @return mixed */ @@ -63,33 +55,6 @@ public function getConfig($slot) return $this->config[$slot]; } - public function getLocalizedPath($slot, $locale = null) - { - $data = $this->getConfig($slot); - - $event = new GenericEvent($this, [ - 'route' => $data - ]); - - \Pimcore::getEventDispatcher()->dispatch( - 'members.path.route', - $event - ); - - if ($event->hasArgument('url')) { - $url = $event->getArgument('url'); - } else { - $lang = ''; - if (!empty($locale)) { - $lang = (string)$locale; - } - - $url = str_replace('/%lang', '/' . $lang, $data); - } - - return $url; - } - /** * @param string $bundleName * diff --git a/src/MembersBundle/CoreExtension/GroupMultiselect.php b/src/MembersBundle/CoreExtension/GroupMultiselect.php index 51611203..c4fc699a 100644 --- a/src/MembersBundle/CoreExtension/GroupMultiselect.php +++ b/src/MembersBundle/CoreExtension/GroupMultiselect.php @@ -4,9 +4,14 @@ use Pimcore\Model\Element; use Pimcore\Model\DataObject; +use Pimcore\Model\DataObject\ClassDefinition\Data\Relations\AbstractRelations; +use MembersBundle\Pimcore\DataObject\ClassDefinition\Data\Traits\ResourceDataTrait; +use MembersBundle\Pimcore\DataObject\ClassDefinition\Data\QueryResourcePersistenceAwareInterface; -class GroupMultiselect extends DataObject\ClassDefinition\Data\Relations\AbstractRelations +class GroupMultiselect extends AbstractRelations implements QueryResourcePersistenceAwareInterface { + use ResourceDataTrait; + /** * Static type of this element. * @@ -14,11 +19,43 @@ class GroupMultiselect extends DataObject\ClassDefinition\Data\Relations\Abstrac */ public $fieldtype = 'membersGroupMultiselect'; + /** + * Type for the column to query + * + * @var string + */ + public $queryColumnType = 'text'; + + /** + * Type for the generated phpdoc + * + * @var string + */ + public $phpdocType = 'array'; + /** * @var bool */ public $relationType = true; + /** + * {@inheritdoc} + */ + public function getQueryColumnType() + { + return 'text'; + } + + /** + * {@inheritdoc} + */ + public function setQueryColumnType($queryColumnType) + { + $this->queryColumnType = $queryColumnType; + + return $this; + } + /** * @param string $data * @param null $object @@ -49,6 +86,7 @@ public function getDataForEditmode($data, $object = null, $params = []) * @param array $data * @param null|DataObject\AbstractObject $object * @param mixed $params + * * @return array */ public function getDataFromEditmode($data, $object = null, $params = []) @@ -75,40 +113,7 @@ public function getDataFromEditmode($data, $object = null, $params = []) * @param $data * @param null $object * @param array $params - * @return array|null - */ - public function getDataForResource($data, $object = null, $params = []) - { - $return = []; - - if (is_array($data) && count($data) > 0) { - $counter = 1; - foreach ($data as $group) { - $return[] = [ - 'src_id' => $object->getId(), - 'dest_id' => $group->getId(), - 'type' => 'object', - 'fieldname' => $this->getName(), - 'index' => $counter - ]; - - $counter++; - } - - return $return; - } elseif (is_array($data) and count($data) === 0) { - //give empty array if data was not null - return []; - } else { - //return null if data was null - this indicates data was not loaded - return null; - } - } - - /** - * @param $data - * @param null $object - * @param array $params + * * @return null|string * @throws \Exception */ @@ -140,6 +145,7 @@ public function getDataForQueryResource($data, $object = null, $params = []) /** * @param $object * @param array $params + * * @return array|mixed|null */ public function preGetData($object, $params = []) @@ -158,46 +164,74 @@ public function preGetData($object, $params = []) * @param array $data * @param null $object * @param array $params + * * @return array */ - public function getDataFromResource($data = [], $object = null, $params = []) + public function loadData($data, $object = null, $params = []) { - $elements = []; - if (is_array($data) && count($data) > 0) { - foreach ($data as $element) { - $e = null; - if ($element['type'] == 'object') { - $e = DataObject::getById($element['dest_id']); - } - if ($e instanceof Element\ElementInterface) { - $elements[] = $e; - } - } - } - - return $elements; + return $this->getDataFromResource($data, $object, $params); } /** * @param array $data * @param null $object * @param array $params + * * @return array */ - public function loadData($data, $object = null, $params = []) + public function prepareDataForPersistence($data, $object = null, $params = []) { - return $this->getDataFromResource($data, $object, $params); + $return = []; + + if (is_array($data) && count($data) > 0) { + $counter = 1; + foreach ($data as $object) { + if ($object instanceof Element\ElementInterface) { + $return[] = [ + 'dest_id' => $object->getId(), + 'type' => Element\Service::getElementType($object), + 'fieldname' => $this->getName(), + 'index' => $counter + ]; + } + $counter++; + } + + return $return; + } elseif (is_array($data) and count($data) === 0) { + //give empty array if data was not null + return []; + } else { + //return null if data was null - this indicates data was not loaded + return null; + } } /** + * BC Layer for pimcore < 5.6 + * * @param array $data * @param null $object * @param array $params + * * @return array */ - public function prepareDataForPersistence($data, $object = null, $params = []) + public function getDataFromResource($data = [], $object = null, $params = []) { - return $this->getDataFromResource($data, $object, $params); + $elements = []; + if (is_array($data) && count($data) > 0) { + foreach ($data as $element) { + $e = null; + if ($element['type'] == 'object') { + $e = DataObject::getById($element['dest_id']); + } + if ($e instanceof Element\ElementInterface) { + $elements[] = $e; + } + } + } + + return $elements; } } diff --git a/src/MembersBundle/Document/Areabrick/MembersLogin/MembersLogin.php b/src/MembersBundle/Document/Areabrick/MembersLogin/MembersLogin.php index daf02a31..d66e9d63 100644 --- a/src/MembersBundle/Document/Areabrick/MembersLogin/MembersLogin.php +++ b/src/MembersBundle/Document/Areabrick/MembersLogin/MembersLogin.php @@ -69,9 +69,9 @@ public function action(Info $info) /** @var $formFactory \MembersBundle\Form\Factory\FactoryInterface */ $form = $this->formFactory->createUnnamedForm($formParams); - $view->form = $form->createView(); + $view->getParameters()->set('form', $form->createView()); foreach ($params as $key => $param) { - $view->{$key} = $param; + $view->getParameters()->set($key, $param); } } 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/ClassManager.php b/src/MembersBundle/Manager/ClassManager.php index 46cb616e..497e63d0 100644 --- a/src/MembersBundle/Manager/ClassManager.php +++ b/src/MembersBundle/Manager/ClassManager.php @@ -22,17 +22,24 @@ public function __construct(Configuration $configuration) } /** - * @return bool + * @inheritdoc */ public function getGroupListing() { - $className = $this->configuration->getConfig('group'); - if (empty($className['adapter']['class_name'])) { + $groupClass = $this->getGroupClass(); + if (!\Pimcore\Tool::classExists($groupClass)) { return false; } - $listing = 'Pimcore\\Model\\DataObject\\' . ucfirst($className['adapter']['class_name']); + return $groupClass::getList(); + } + /** + * @inheritdoc + */ + public function getUserListing() + { + $listing = $this->getUserClass(); if (!\Pimcore\Tool::classExists($listing)) { return false; } @@ -41,34 +48,29 @@ public function getGroupListing() } /** - * @return bool + * @inheritdoc */ - public function getUserListing() + public function getGroupClass() { - $className = $this->configuration->getConfig('user'); - + $className = $this->configuration->getConfig('group'); if (empty($className['adapter']['class_name'])) { - return false; + return ''; } - $listing = 'Pimcore\\Model\\DataObject\\' . ucfirst($className['adapter']['class_name']); - - if (!\Pimcore\Tool::classExists($listing)) { - return false; - } + $class = 'Pimcore\\Model\\DataObject\\' . ucfirst($className['adapter']['class_name']); - return $listing::getList(); + return $class; } /** - * @return bool|string + * @inheritdoc */ public function getUserClass() { $className = $this->configuration->getConfig('user'); if (empty($className['adapter']['class_name'])) { - return false; + return ''; } $class = 'Pimcore\\Model\\DataObject\\' . ucfirst($className['adapter']['class_name']); diff --git a/src/MembersBundle/Manager/ClassManagerInterface.php b/src/MembersBundle/Manager/ClassManagerInterface.php index d9f8d329..c6117f9e 100644 --- a/src/MembersBundle/Manager/ClassManagerInterface.php +++ b/src/MembersBundle/Manager/ClassManagerInterface.php @@ -2,20 +2,27 @@ namespace MembersBundle\Manager; +use Pimcore\Model\DataObject\Listing; + interface ClassManagerInterface { /** - * @return bool + * @return Listing */ public function getGroupListing(); /** - * @return bool + * @return Listing */ public function getUserListing(); /** - * @return bool|string + * @return string + */ + public function getGroupClass(); + + /** + * @return string */ public function getUserClass(); } \ No newline at end of file diff --git a/src/MembersBundle/Manager/UserManager.php b/src/MembersBundle/Manager/UserManager.php index ea2ee489..0a4b5262 100644 --- a/src/MembersBundle/Manager/UserManager.php +++ b/src/MembersBundle/Manager/UserManager.php @@ -4,7 +4,6 @@ use MembersBundle\Adapter\User\UserInterface; use MembersBundle\Configuration\Configuration; -use Pimcore\Model\Listing\AbstractListing; use Pimcore\Model\DataObject; use Pimcore\Model\Version; @@ -26,7 +25,10 @@ class UserManager implements UserManagerInterface protected $memberStorageId; /** - * {@inheritdoc} + * UserManager constructor. + * + * @param Configuration $configuration + * @param ClassManagerInterface $classManager */ public function __construct(Configuration $configuration, ClassManagerInterface $classManager) { @@ -60,7 +62,6 @@ public function deleteUser(UserInterface $user) */ public function findUserByConfirmationToken($token, $includeUnpublished = true) { - /** @var AbstractListing $memberListing */ $memberListing = $this->classManager->getUserListing(); $memberListing->setCondition('confirmationToken = ?', [$token]); $memberListing->setUnpublished($includeUnpublished); @@ -79,7 +80,6 @@ public function findUserByConfirmationToken($token, $includeUnpublished = true) */ public function findUserByEmail($emailAddress, $includeUnpublished = true) { - /** @var AbstractListing $memberListing */ $memberListing = $this->classManager->getUserListing(); $memberListing->setCondition('email = ?', [$emailAddress]); $memberListing->setUnpublished($includeUnpublished); @@ -98,7 +98,6 @@ public function findUserByEmail($emailAddress, $includeUnpublished = true) */ public function findUserByUsername($username, $includeUnpublished = true) { - /** @var AbstractListing $memberListing */ $memberListing = $this->classManager->getUserListing(); $memberListing->setCondition('userName = ?', [$username]); $memberListing->setUnpublished($includeUnpublished); @@ -117,7 +116,6 @@ public function findUserByUsername($username, $includeUnpublished = true) */ public function findUserByCondition($condition = '', $conditionVariables = [], $includeUnpublished = true, $returnSingle = true) { - /** @var AbstractListing $memberListing */ $memberListing = $this->classManager->getUserListing(); $memberListing->setCondition($condition, $conditionVariables); $memberListing->setUnpublished($includeUnpublished); @@ -148,7 +146,6 @@ public function findUserByUsernameOrEmail($usernameOrEmail) */ public function findUsers() { - /** @var AbstractListing $memberListing */ $memberListing = $this->classManager->getUserListing(); return $memberListing->load(); @@ -186,7 +183,7 @@ public function updateUser(UserInterface $user, $properties = []) $user = $this->setupNewUser($user); } - // update page properties. + // update user properties. if (!empty($properties)) { foreach ($properties as $propKey => $propValue) { $user->setProperty($propKey, 'text', $propValue, false); @@ -224,7 +221,6 @@ private function setupNewUser(UserInterface $user) } $objects = $listing->getObjects(); - if (count($objects) > 0) { $userGroups[] = $objects[0]; } diff --git a/src/MembersBundle/Manager/UserManagerInterface.php b/src/MembersBundle/Manager/UserManagerInterface.php index 4611b0c2..9200f4d0 100644 --- a/src/MembersBundle/Manager/UserManagerInterface.php +++ b/src/MembersBundle/Manager/UserManagerInterface.php @@ -7,27 +7,28 @@ interface UserManagerInterface { /** - * @return bool|string + * @return string */ public function getClass(); /** * @param UserInterface $user + * * @return mixed */ public function deleteUser(UserInterface $user); /** - * @param $token - * @param bool $includeUnpublished + * @param string $token + * @param bool $includeUnpublished * * @return null|UserInterface */ public function findUserByConfirmationToken($token, $includeUnpublished = true); /** - * @param $emailAddress - * @param bool $includeUnpublished + * @param string $emailAddress + * @param bool $includeUnpublished * * @return null|UserInterface */ @@ -46,12 +47,14 @@ public function findUserByUsername($username, $includeUnpublished = true); * @param array $conditionVariables * @param bool $includeUnpublished * @param bool $returnSingle + * * @return null|array|UserInterface */ public function findUserByCondition($condition = '', $conditionVariables = [], $includeUnpublished = true, $returnSingle = true); /** - * @param $usernameOrEmail + * @param string $usernameOrEmail + * * @return null|array|UserInterface */ public function findUserByUsernameOrEmail($usernameOrEmail); @@ -63,6 +66,7 @@ public function findUsers(); /** * @param UserInterface $user + * * @return mixed */ public function reloadUser(UserInterface $user); diff --git a/src/MembersBundle/Pimcore/DataObject/ClassDefinition/Data/QueryResourcePersistenceAwareInterface.php b/src/MembersBundle/Pimcore/DataObject/ClassDefinition/Data/QueryResourcePersistenceAwareInterface.php new file mode 100644 index 00000000..887f77f4 --- /dev/null +++ b/src/MembersBundle/Pimcore/DataObject/ClassDefinition/Data/QueryResourcePersistenceAwareInterface.php @@ -0,0 +1,13 @@ + 0) { + $counter = 1; + foreach ($data as $group) { + $return[] = [ + 'src_id' => $object->getId(), + 'dest_id' => $group->getId(), + 'type' => 'object', + 'fieldname' => $this->getName(), + 'index' => $counter + ]; + + $counter++; + } + + return $return; + } elseif (is_array($data) and count($data) === 0) { + //give empty array if data was not null + return []; + } else { + //return null if data was null - this indicates data was not loaded + return null; + } + } + } +} \ No newline at end of file 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/src/MembersBundle/Resources/config/services/profile.yml b/src/MembersBundle/Resources/config/services/profile.yml index 9980c005..d24fa9e9 100644 --- a/src/MembersBundle/Resources/config/services/profile.yml +++ b/src/MembersBundle/Resources/config/services/profile.yml @@ -3,6 +3,7 @@ services: #form profile factory members.profile.form.factory: class: MembersBundle\Form\Factory\FormFactory + public: true arguments: - '@form.factory' - '%members_user.profile.form.name%' diff --git a/src/MembersBundle/Resources/config/services/registration.yml b/src/MembersBundle/Resources/config/services/registration.yml index b50d40b0..eebae28b 100644 --- a/src/MembersBundle/Resources/config/services/registration.yml +++ b/src/MembersBundle/Resources/config/services/registration.yml @@ -3,6 +3,7 @@ services: #form registration factory members.registration.form.factory: class: MembersBundle\Form\Factory\FormFactory + public: true arguments: - '@form.factory' - '%members_user.registration.form.name%' diff --git a/src/MembersBundle/Resources/config/services/resetting.yml b/src/MembersBundle/Resources/config/services/resetting.yml index 45c4ca11..42f8a77a 100644 --- a/src/MembersBundle/Resources/config/services/resetting.yml +++ b/src/MembersBundle/Resources/config/services/resetting.yml @@ -3,6 +3,7 @@ services: #form resetting request factory members.resetting_request.form.factory: class: MembersBundle\Form\Factory\FormFactory + public: true arguments: - '@form.factory' - '%members_user.resetting_request.form.name%' @@ -18,6 +19,7 @@ services: #form resetting factory members.resetting.form.factory: class: MembersBundle\Form\Factory\FormFactory + public: true arguments: - '@form.factory' - '%members_user.resetting.form.name%' diff --git a/src/MembersBundle/Resources/install/classes/class_MembersUser_export.json b/src/MembersBundle/Resources/install/classes/class_MembersUser_export.json index 7ed4bd1e..fa9562d4 100644 --- a/src/MembersBundle/Resources/install/classes/class_MembersUser_export.json +++ b/src/MembersBundle/Resources/install/classes/class_MembersUser_export.json @@ -1,7 +1,9 @@ { "description": null, "parentClass": "\\MembersBundle\\Adapter\\User\\AbstractUser", + "listingParentClass": null, "useTraits": null, + "listingUseTraits": null, "allowInherit": false, "allowVariants": false, "showVariants": false, @@ -16,7 +18,7 @@ "width": null, "height": null, "collapsible": false, - "collapsed": null, + "collapsed": false, "bodyStyle": null, "datatype": "layout", "permissions": null, @@ -45,6 +47,8 @@ "columnLength": 190, "phpdocType": "string", "regex": "", + "unique": null, + "showCharCount": null, "name": "userName", "title": "User Name", "tooltip": "", @@ -68,6 +72,8 @@ "columnLength": 190, "phpdocType": "string", "regex": "", + "unique": null, + "showCharCount": null, "name": "email", "title": "email", "tooltip": "", @@ -91,6 +97,8 @@ "columnLength": 190, "phpdocType": "string", "regex": "", + "unique": null, + "showCharCount": null, "name": "confirmationToken", "title": "Confirmation Token", "tooltip": "", @@ -190,11 +198,11 @@ "style": "", "permissions": null, "datatype": "data", - "columnType": "text", - "queryColumnType": "text", "invisible": false, "visibleGridView": false, - "visibleSearch": false + "visibleSearch": false, + "queryColumnType": "text", + "phpdocType": "array" } ], "locked": false @@ -205,9 +213,11 @@ "icon": "\/bundles\/members\/img\/objectUser.svg", "previewUrl": null, "group": null, + "linkGeneratorReference": null, "propertyVisibility": { "grid": { "id": true, + "key": false, "path": true, "published": true, "modificationDate": true, @@ -215,6 +225,7 @@ }, "search": { "id": true, + "key": false, "path": true, "published": true, "modificationDate": true, diff --git a/src/MembersBundle/Tool/Install.php b/src/MembersBundle/Tool/Install.php index 676ae3cf..7a7816c9 100644 --- a/src/MembersBundle/Tool/Install.php +++ b/src/MembersBundle/Tool/Install.php @@ -289,8 +289,8 @@ public function installFolder() throw new AbortMigrationException(sprintf('Failed to install protected asset folder. error was: "%s"', $e->getMessage())); } - //now create .htaccess file to disallow every request to this folder (exept admin! - $f = fopen(PIMCORE_ASSET_DIRECTORY . $folder->getFullPath() . '/.htaccess', 'a+'); + //now create .htaccess file to disallow every request to this folder (except admin)! + $f = fopen(PIMCORE_ASSET_DIRECTORY . $folder->getFullPath() . '/.htaccess', 'w+'); $rule = 'RewriteEngine On' . "\n"; $rule .= 'RewriteCond %{HTTP_HOST}==%{HTTP_REFERER} !^(.*?)==https?://\1/admin/ [OR]' . "\n"; diff --git a/tests/_data/.gitkeep b/tests/_data/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/_envs/local.yml b/tests/_envs/local.yml new file mode 100644 index 00000000..e69de29b diff --git a/tests/_envs/travis.yml b/tests/_envs/travis.yml new file mode 100644 index 00000000..9d8c54ce --- /dev/null +++ b/tests/_envs/travis.yml @@ -0,0 +1,10 @@ +modules: + config: + \DachcomBundle\Test\Helper\Browser\WebDriver: + browser: chrome + port: 9515 + capabilities: + chromeOptions: + args: ['--headless', '--disable-gpu', '--no-sandbox', '--window-size=1024,768'] + prefs: + download.default_directory: '%TRAVIS_BUILD_DIR%/lib/Members/tests/_data/downloads' \ No newline at end of file diff --git a/tests/_support/AcceptanceTester.php b/tests/_support/AcceptanceTester.php new file mode 100644 index 00000000..ed1e3330 --- /dev/null +++ b/tests/_support/AcceptanceTester.php @@ -0,0 +1,13 @@ + 'checkStaticRoute' + ]; + } + + public function checkStaticRoute(StaticRouteEvent $event) + { + if($event->getRouteName() !== 'test_route') { + return; + } + + $request = $event->getRequest(); + $object = TestClass::getById($request->attributes->get('object_id')); + + $event->setStaticRouteObject($object); + } +} diff --git a/tests/_support/App/TestAppKernel.php b/tests/_support/App/TestAppKernel.php new file mode 100644 index 00000000..c5c9a3c9 --- /dev/null +++ b/tests/_support/App/TestAppKernel.php @@ -0,0 +1,62 @@ +load($bundleClass . '/etc/config/bundle/symfony/' . $configName); + } + } + + /** + * {@inheritdoc} + */ + public function registerBundlesToCollection(\Pimcore\HttpKernel\BundleCollection\BundleCollection $collection) + { + if (class_exists('\\AppBundle\\AppBundle')) { + $collection->addBundle(new \AppBundle\AppBundle()); + } + + $collection->addBundle(new \Symfony\Bundle\WebProfilerBundle\WebProfilerBundle()); + + $bundleClass = getenv('DACHCOM_BUNDLE_CLASS'); + $collection->addBundle(new $bundleClass()); + } + + /** + * @param ContainerBuilder $container + */ + protected function build(ContainerBuilder $container) + { + $container->addCompilerPass(new \DachcomBundle\Test\DependencyInjection\MakeServicesPublicPass(), + \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, -100000); + $container->addCompilerPass(new \DachcomBundle\Test\DependencyInjection\MonologChannelLoggerPass(), + \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 1); + } + + /** + * {@inheritdoc} + */ + public function boot() + { + parent::boot(); + \Pimcore::setKernel($this); + } +} diff --git a/tests/_support/DependencyInjection/MakeServicesPublicPass.php b/tests/_support/DependencyInjection/MakeServicesPublicPass.php new file mode 100644 index 00000000..13736db2 --- /dev/null +++ b/tests/_support/DependencyInjection/MakeServicesPublicPass.php @@ -0,0 +1,30 @@ +getServiceIds(), function (string $id) use ($prefix) { + return strpos($id, $prefix) === 0; + }); + + foreach ($serviceIds as $serviceId) { + if ($container->hasAlias($serviceId)) { + $container->getAlias($serviceId)->setPublic(true); + } + + $container + ->findDefinition($serviceId) + ->setPublic(true); + } + } +} diff --git a/tests/_support/DependencyInjection/MonologChannelLoggerPass.php b/tests/_support/DependencyInjection/MonologChannelLoggerPass.php new file mode 100644 index 00000000..91f88757 --- /dev/null +++ b/tests/_support/DependencyInjection/MonologChannelLoggerPass.php @@ -0,0 +1,27 @@ +getParameter('monolog.handlers_to_channels'); + foreach ($channelsToHide as $channelToHide) { + $monologHandlers['monolog.handler.console']['elements'][] = $channelToHide; + } + + $container->setParameter('monolog.handlers_to_channels', $monologHandlers); + } +} diff --git a/tests/_support/FunctionalTester.php b/tests/_support/FunctionalTester.php new file mode 100644 index 00000000..862e9c1d --- /dev/null +++ b/tests/_support/FunctionalTester.php @@ -0,0 +1,13 @@ + 'PhpBrowser needs the pimcore core framework to work.' + ]; + } + + /** + * @param PimcoreCore $pimcoreCore + */ + public function _inject($pimcoreCore) + { + $this->pimcoreCore = $pimcoreCore; + } + + /** + * @inheritDoc + */ + public function _initialize() + { + $this->sessionSnapShot = []; + + parent::_initialize(); + } + + /** + * Actor Function to see a page with enabled edit-mode + * + * @param string $page + */ + public function amOnPageInEditMode(string $page) + { + $this->pimcoreCore->amOnPage(sprintf('%s?pimcore_editmode=true', $page)); + } + + /** + * Actor Function to see if Link is a download file + * + * @param AbstractModel $element + * @param string $link + */ + public function seeDownloadLink(AbstractModel $element, string $link) + { + $this->pimcoreCore->_loadPage('HEAD', $link); + $response = $this->pimcoreCore->client->getInternalResponse(); + $headers = $response->getHeaders(); + + $contentDisposition = sprintf('attachment; filename="%s"', $element->getKey()); + + $this->assertEquals(200, $response->getStatus()); + $this->assertEquals($contentDisposition, $headers['content-disposition'][0]); + $this->assertEquals($element->getMimetype(), $headers['content-type'][0]); + } + + /** + * Actor Function to see if Link is a download file + * + * @param string $fileName + * @param string $link + */ + public function seeDownloadLinkZip(string $fileName, string $link) + { + $this->pimcoreCore->_loadPage('HEAD', $link); + $response = $this->pimcoreCore->client->getInternalResponse(); + $headers = $response->getHeaders(); + + $contentDisposition = sprintf('attachment; filename="%s"', $fileName); + + $this->assertEquals(200, $response->getStatus()); + $this->assertEquals($contentDisposition, $headers['content-disposition'][0]); + $this->assertEquals('application/zip', $headers['content-type'][0]); + } + + /** + * Actor Function to see a page generated by a static route definition. + * + * @param string $routeName + * @param array $args + */ + public function amOnStaticRoute(string $routeName, array $args) + { + $path = $this->pimcoreCore->getContainer()->get('router')->generate($routeName, $args, false); + $this->pimcoreCore->amOnPage($path); + } + + /** + * Actor Function to see a editable on current page. + * + * @param string $name + * @param string $type + * @param array $options + * @param null $data + * @param null $selector + */ + public function seeAEditableConfiguration(string $name, string $type, array $options, $data = null, $selector = null) + { + $this->pimcoreCore->see(MembersHelper::generateEditableConfiguration($name, $type, $options, $data), $selector); + } + + /** + * Actor Function to see if given email has been with specified address + * Only works with PhpBrowser (Symfony Client) + * + * @param string $recipient + * @param Email $email + */ + public function seeEmailIsSentTo(string $recipient, Email $email) + { + $collectedMessages = $this->getCollectedEmails($email); + + $recipients = []; + foreach ($collectedMessages as $message) { + if ($email->getSubject() !== $message->getSubject()) { + continue; + } + $recipients = array_merge($recipients, $message->getTo()); + } + + $this->assertContains($recipient, array_keys($recipients)); + + } + + /** + * Actor Function to see if given email has been sent + * + * @param Email $email + * @param string $property + * @param string $value + */ + public function seeSentEmailHasPropertyValue(Email $email, string $property, string $value) + { + $collectedMessages = $this->getCollectedEmails($email); + + $getter = 'get' . ucfirst($property); + foreach ($collectedMessages as $message) { + $getterData = $message->$getter(); + if (is_array($getterData)) { + $this->assertContains($value, array_keys($getterData)); + } else { + $this->assertEquals($value, $getterData); + } + } + } + + /** + * Actor Function to login into Members FrontEnd + * + * @param UserInterface $membersUser + */ + public function amLoggedInAsFrontendUser(UserInterface $membersUser) + { + $firewallName = 'members_fe'; + + if (!$membersUser instanceof UserInterface) { + $this->debug(sprintf('[PIMCORE BUNDLE MODULE] user needs to be a instance of %s.', UserInterface::class)); + return; + } + + /** @var Session $session */ + $session = $this->pimcoreCore->getContainer()->get('session'); + + $token = new UsernamePasswordToken($membersUser, null, $firewallName, $membersUser->getRoles()); + $this->pimcoreCore->getContainer()->get('security.token_storage')->setToken($token); + + $session->set('_security_' . $firewallName, serialize($token)); + $session->save(); + + $cookie = new Cookie($session->getName(), $session->getId()); + + $this->pimcoreCore->client->getCookieJar()->clear(); + $this->pimcoreCore->client->getCookieJar()->set($cookie); + + } + + /** + * Actor Function to login into Pimcore Backend + * + * @param $username + */ + public function amLoggedInAs($username) + { + $firewallName = 'admin'; + + try { + /** @var PimcoreUser $userModule */ + $userModule = $this->getModule('\\' . PimcoreUser::class); + } catch (ModuleException $pimcoreModule) { + $this->debug('[PIMCORE BUNDLE MODULE] could not load pimcore user module'); + return; + } + + $pimcoreUser = $userModule->getUser($username); + + if (!$pimcoreUser instanceof User) { + $this->debug(sprintf('[PIMCORE BUNDLE MODULE] could not fetch user %s.', $username)); + return; + } + + /** @var Session $session */ + $session = $this->pimcoreCore->getContainer()->get('session'); + + $user = new \Pimcore\Bundle\AdminBundle\Security\User\User($pimcoreUser); + $token = new UsernamePasswordToken($user, null, $firewallName, $pimcoreUser->getRoles()); + $this->pimcoreCore->getContainer()->get('security.token_storage')->setToken($token); + + \Pimcore\Tool\Session::useSession(function (AttributeBagInterface $adminSession) use ($pimcoreUser, $session) { + $session->setId(\Pimcore\Tool\Session::getSessionId()); + $adminSession->set('user', $pimcoreUser); + $adminSession->set('csrfToken', self::PIMCORE_ADMIN_CSRF_TOKEN_NAME); + }); + + // allow re-usage of session in same cest. + if (!empty($this->sessionSnapShot)) { + $cookie = $this->sessionSnapShot; + } else { + $cookie = new Cookie($session->getName(), $session->getId()); + $this->sessionSnapShot = $cookie; + } + + $this->pimcoreCore->client->getCookieJar()->clear(); + $this->pimcoreCore->client->getCookieJar()->set($cookie); + + } + + /** + * Actor Function to send tokenized ajax request in backend + * + * @param string $url + * @param array $params + */ + public function sendTokenAjaxPostRequest(string $url, array $params = []) + { + $params['csrfToken'] = self::PIMCORE_ADMIN_CSRF_TOKEN_NAME; + $this->pimcoreCore->sendAjaxPostRequest($url, $params); + } + + /** + * @param Email $email + * + * @return array + */ + protected function getCollectedEmails(Email $email) + { + $this->assertInstanceOf(Email::class, $email); + + /** @var Profiler $profiler */ + $profiler = $this->pimcoreCore->_getContainer()->get('profiler'); + + $tokens = $profiler->find('', '', 1, 'POST', '', ''); + if (count($tokens) === 0) { + throw new \RuntimeException('No profile found. Is the profiler data collector enabled?'); + } + + $token = $tokens[0]['token']; + /** @var \Symfony\Component\HttpKernel\Profiler\Profile $profile */ + $profile = $profiler->loadProfile($token); + + if (!$profile instanceof Profile) { + throw new \RuntimeException(sprintf('Profile with token "%s" not found.', $token)); + } + + /** @var MessageDataCollector $mailCollector */ + $mailCollector = $profile->getCollector('swiftmailer'); + + $this->assertGreaterThan(0, $mailCollector->getMessageCount()); + + $collectedMessages = $mailCollector->getMessages(); + + $emails = []; + /** @var \Pimcore\Mail $message */ + foreach ($collectedMessages as $message) { + if ($email->getProperty('test_identifier') !== $message->getDocument()->getProperty('test_identifier')) { + continue; + } + $emails[] = $message; + } + + return $emails; + + } + + /** + * Actor Function to see if last executed request is in given path + * + * @param string $expectedPath + */ + public function seeLastRequestIsInPath(string $expectedPath) + { + $requestUri = $this->pimcoreCore->client->getInternalRequest()->getUri(); + $requestServer = $this->pimcoreCore->client->getInternalRequest()->getServer(); + + $expectedUri = sprintf('http://%s%s', $requestServer['HTTP_HOST'], $expectedPath); + + $this->assertEquals($expectedUri, $requestUri); + } + + /** + * Actor Function to check if last _fragment request has given properties in request attributes. + * + * @param array $properties + */ + public function seePropertiesInLastFragmentRequest(array $properties = []) + { + /** @var Profiler $profiler */ + $profiler = $this->pimcoreCore->_getContainer()->get('profiler'); + + $tokens = $profiler->find('', '_fragment', 1, 'GET', '', ''); + if (count($tokens) === 0) { + throw new \RuntimeException('No profile found. Is the profiler data collector enabled?'); + } + + $token = $tokens[0]['token']; + /** @var \Symfony\Component\HttpKernel\Profiler\Profile $profile */ + $profile = $profiler->loadProfile($token); + + if (!$profile instanceof Profile) { + throw new \RuntimeException(sprintf('Profile with token "%s" not found.', $token)); + } + + /** @var RequestDataCollector $requestCollector */ + $requestCollector = $profile->getCollector('request'); + + foreach ($properties as $property) { + $this->assertTrue($requestCollector->getRequestAttributes()->has($property), sprintf('"%s" not found in request collector.', $property)); + } + } +} diff --git a/tests/_support/Helper/Browser/WebDriver.php b/tests/_support/Helper/Browser/WebDriver.php new file mode 100644 index 00000000..de969453 --- /dev/null +++ b/tests/_support/Helper/Browser/WebDriver.php @@ -0,0 +1,62 @@ +amOnPage(sprintf('%s?pimcore_editmode=true', $page)); + } + + /** + * @param null $path + */ + public function setDownloadPathForWebDriver($path = null) + { + if (is_null($path)) { + $path = FileGeneratorHelper::getDownloadPath(); + } + + $url = $this->webDriver->getCommandExecutor()->getAddressOfRemoteServer(); + $uri = '/session/' . $this->webDriver->getSessionID() . '/chromium/send_command'; + $body = [ + 'cmd' => 'Page.setDownloadBehavior', + 'params' => ['behavior' => 'allow', 'downloadPath' => $path] + ]; + + $client = new \GuzzleHttp\Client(); + $response = $client->post($url . $uri, ['body' => json_encode($body)]); + + try { + $responseData = json_decode($response->getBody()->getContents(), true); + } catch (\Exception $e) { + $responseData = []; + } + + $this->assertArrayHasKey('status', $responseData); + $this->assertEquals(0, $responseData['status']); + + } + + /** + * @param string $name + * @param string $type + * @param array $options + * @param null $data + * @param null $selector + */ + public function seeAEditableConfiguration(string $name, string $type, array $options, $data = null, $selector = null) + { + $this->see(MembersHelper::generateEditableConfiguration($name, $type, $options, $data), $selector); + } +} diff --git a/tests/_support/Helper/MembersFrontend.php b/tests/_support/Helper/MembersFrontend.php new file mode 100644 index 00000000..af9e093e --- /dev/null +++ b/tests/_support/Helper/MembersFrontend.php @@ -0,0 +1,277 @@ + 'MembersFrontend needs the PimcoreBackend module to work.']; + } + + /** + * @param PimcoreBackend $connection + */ + public function _inject(PimcoreBackend $connection) + { + $this->pimcoreBackend = $connection; + } + + /** + * Actor Function to create a frontend user group. + * + * @param string $name + * + * @return DataObject\MembersGroup + * @throws \Exception + */ + public function haveAFrontendUserGroup(string $name = 'Group 1') + { + $group = new DataObject\MembersGroup(); + $group->setKey(File::getValidFilename($name)); + $group->setName($name); + $group->setPublished(true); + $group->setParent(DataObject::getByPath('/')); + $group->save(); + + $this->assertInstanceOf(GroupInterface::class, $group); + + return $group; + } + + /** + * Actor Function to create a fully registered frontend user. Confirmation is optionally. + * + * @param bool $confirmed + * @param array $groups + * + * @return mixed + * @throws \Codeception\Exception\ModuleException + */ + public function haveARegisteredFrontEndUser(bool $confirmed = false, array $groups = []) + { + $configuration = $this->getContainer()->get(Configuration::class); + $membersStoreObject = DataObject::getByPath($configuration->getConfig('storage_path')); + + $userManager = $this->getContainer()->get(UserManager::class); + $userObject = $userManager->createUser(); + + $userObject->setParent($membersStoreObject); + $userObject->setEmail(MembersHelper::DEFAULT_FEU_EMAIL); + $userObject->setUserName(MembersHelper::DEFAULT_FEU_USERNAME); + $userObject->setPlainPassword(MembersHelper::DEFAULT_FEU_PASSWORD); + $userObject->setPublished(false); + + $user = $userManager->updateUser($userObject); + + if (count($groups) > 0) { + $user->setGroups($groups); + $userManager->updateUser($user); + } + + if ($confirmed === true) { + $this->publishAndConfirmAFrontendUser($user); + } + + $this->assertInstanceOf(UserInterface::class, $user); + + return $user; + } + + /** + * Actor Function to publish and confirm (triggered by updateUser()) a frontend user. + * + * @param UserInterface $user + * + * @throws \Codeception\Exception\ModuleException + */ + public function publishAndConfirmAFrontendUser(UserInterface $user) + { + $user->setPublished(true); + + $userManager = $this->getContainer()->get(UserManager::class); + $userManager->updateUser($user); + + $this->assertTrue($user->getPublished()); + } + + /** + * Actor function to see a logged in frontend user in session bag. + * + * @throws \Codeception\Exception\ModuleException + */ + public function seeALoggedInFrontEndUser() + { + $tokenStorage = $this->getContainer()->get('security.token_storage'); + + $this->assertNotNull($tokenStorage->getToken()); + $this->assertInstanceOf(UserInterface::class, $tokenStorage->getToken()->getUser()); + } + + /** + * Actor Function to see a not logged in frontend user in session bag. + * + * @throws \Codeception\Exception\ModuleException + */ + public function seeANotLoggedInFrontEndUser() + { + $tokenStorage = $this->getContainer()->get('security.token_storage'); + + // null is ok in this case! + if (is_null($tokenStorage->getToken())) { + return; + } + + $this->assertSame('anon.', $tokenStorage->getToken()->getUser()); + } + + /** + * Actor Function to see properties in members user object + * + * @param UserInterface $user + * @param array $expectedProperties + */ + public function seePropertiesInFrontendUser(UserInterface $user, array $expectedProperties = []) + { + $userProperties = $user->getProperties(); + foreach ($expectedProperties as $property) { + $this->assertArrayHasKey($property, $userProperties); + } + } + + /** + * Actor Function to get confirmation link from email + * + * @param Email $email + * + * @return string + */ + 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; + } + + /** + * Actor Function to check if no users are available in storage. + * + * @throws \Exception + */ + public function seeNoFrontendUserInStorage() + { + $list = MembersUser::getList(['unpublished' => true]); + $users = $list->load(); + + $this->assertCount(0, $users); + } + + /** + * Actor Function to check if the last registered user has an valid token. + * + * @throws \Exception + */ + public function seeAUserWithValidToken() + { + $user = $this->grabOneUserAfterRegistration(); + $this->assertNotEmpty($user->getConfirmationToken()); + } + + /** + * Actor Function to check if the last registered user has an invalid token. + * + * @throws \Exception + */ + public function seeAUserWithInvalidatedToken() + { + $user = $this->grabOneUserAfterRegistration(); + $this->assertNull($user->getConfirmationToken()); + } + + /** + * Actor Function to check if the last registered user is published. + * + * @throws \Exception + */ + public function seeAPublishedUserAfterRegistration() + { + $user = $this->grabOneUserAfterRegistration(); + $this->assertTrue($user->getPublished()); + } + + /** + * Actor Function to check if the last registered user is unpublished. + * + * @throws \Exception + */ + public function seeAUnpublishedUserAfterRegistration() + { + $user = $this->grabOneUserAfterRegistration(); + $this->assertFalse($user->getPublished()); + } + + /** + * Actor function to get the last registered frontend user. + * Only one user in storage is allowed here. + * + * @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/MembersRestriction.php b/tests/_support/Helper/MembersRestriction.php new file mode 100644 index 00000000..24dacedc --- /dev/null +++ b/tests/_support/Helper/MembersRestriction.php @@ -0,0 +1,191 @@ +setParent($parent); + } + + $object->save(); + + $this->assertInstanceOf($type, $object); + + return $object; + } + + /** + * @param AbstractObject $object + * @param array $groups + * @param bool $inherit + * @param bool $inherited + */ + public function addRestrictionToObject(AbstractObject $object, $groups = [], $inherit = false, $inherited = false) + { + $restriction = $this->createElementRestriction($object, 'object', $groups, $inherit, $inherited); + $this->assertInstanceOf(Restriction::class, $restriction); + } + + /** + * @param string $key + * + * @return Asset\Image + * @throws \Exception + */ + public function haveAPimcoreAsset($key = 'restricted-asset') + { + $asset = TestHelper::createImageAsset($key, false, false); + $asset->setParent(Asset::getByPath('/' . RestrictionUri::PROTECTED_ASSET_FOLDER)); + $asset->save(); + + $this->assertInstanceOf(Asset::class, $asset); + + return $asset; + } + + /** + * @param Asset $asset + * @param array $groups + * @param bool $inherit + * @param bool $inherited + */ + public function addRestrictionToAsset(Asset $asset, $groups = [], $inherit = false, $inherited = false) + { + $restriction = $this->createElementRestriction($asset, 'asset', $groups, $inherit, $inherited); + $this->assertInstanceOf(Restriction::class, $restriction); + } + + /** + * @param string $key + * @param null $parent + * + * @return Document\Page + * @throws \Exception + */ + public function haveAPimcoreDocument($key = 'restricted-document', $parent = null) + { + $document = TestHelper::createEmptyDocumentPage($key, false); + + if ($parent !== null) { + $document->setParent($parent); + } + + $document->save(); + + $this->assertInstanceOf(Document::class, $document); + + return $document; + } + + /** + * @param Document $document + * @param array $groups + * @param bool $inherit + * @param bool $inherited + */ + public function addRestrictionToDocument(Document $document, $groups = [], $inherit = false, $inherited = false) + { + $restriction = $this->createElementRestriction($document, 'page', $groups, $inherit, $inherited); + $this->assertInstanceOf(Restriction::class, $restriction); + } + + /** + * Actor Function to generate asset download link with containing a single asset file. + * + * @param Asset $asset + * + * @return string + * @throws \Codeception\Exception\ModuleException + * @throws \Exception + */ + public function haveASingleAssetDownloadLink(Asset $asset) + { + $downloadLink = $this + ->getContainer()->get(RestrictionUri::class) + ->generateAssetUrl($asset); + + $this->assertInternalType('string', $downloadLink); + + return $downloadLink; + } + + /** + * Actor Function to generate asset download link with containing multiple assets. + * + * @param array $assets + * + * @return string + * @throws \Codeception\Exception\ModuleException + * @throws \Exception + */ + public function haveAMultipleAssetDownloadLink(array $assets) + { + $downloadLink = $this + ->getContainer()->get(RestrictionUri::class) + ->generateAssetPackageUrl($assets); + + $this->assertInternalType('string', $downloadLink); + + return $downloadLink; + } + + /** + * @param $element + * @param string $type + * @param array $groups + * @param bool $inherit + * @param bool $inherited + * + * @return Restriction + */ + protected function createElementRestriction( + $element, + string $type = 'page', + array $groups = [], + bool $inherit = false, + bool $inherited = false + ) { + $restriction = new Restriction(); + $restriction->setTargetId($element->getId()); + $restriction->setCtype($type); + $restriction->setInherit($inherit); + $restriction->setIsInherited($inherited); + $restriction->setRelatedGroups($groups); + $restriction->save(); + + return $restriction; + + } + + /** + * @return Container + * @throws \Codeception\Exception\ModuleException + */ + protected function getContainer() + { + return $this->getModule('\\' . PimcoreCore::class)->getContainer(); + } +} diff --git a/tests/_support/Helper/PimcoreAdminJson.php b/tests/_support/Helper/PimcoreAdminJson.php new file mode 100644 index 00000000..6962e92e --- /dev/null +++ b/tests/_support/Helper/PimcoreAdminJson.php @@ -0,0 +1,58 @@ + 'PimcoreAdminJson needs a valid browser to work.']; + } + + /** + * @param InnerBrowser $connection + */ + public function _inject(InnerBrowser $connection) + { + $this->connectionModule = $connection; + } + + public function seeResponseContainsJson($json = []) + { + \PHPUnit_Framework_Assert::assertThat( + $this->connectionModule->_getResponseContent(), + new JsonContains($json) + ); + } + + public function seeResponseIsJson() + { + $responseContent = $this->connectionModule->_getResponseContent(); + \PHPUnit_Framework_Assert::assertNotEquals('', $responseContent, 'response is empty'); + json_decode($responseContent); + $errorCode = json_last_error(); + $errorMessage = json_last_error_msg(); + \PHPUnit_Framework_Assert::assertEquals( + JSON_ERROR_NONE, + $errorCode, + sprintf( + "Invalid json: %s. System message: %s.", + $responseContent, + $errorMessage + ) + ); + } +} diff --git a/tests/_support/Helper/PimcoreBackend.php b/tests/_support/Helper/PimcoreBackend.php new file mode 100644 index 00000000..0a30cb40 --- /dev/null +++ b/tests/_support/Helper/PimcoreBackend.php @@ -0,0 +1,608 @@ +generatePageDocument($documentKey, $action, $controller, $locale); + + try { + $document->save(); + } catch (\Exception $e) { + \Codeception\Util\Debug::debug(sprintf('[MEMBERS ERROR] error while saving document page. message was: ' . $e->getMessage())); + } + + $this->assertInstanceOf(Page::class, Page::getById($document->getId())); + + return $document; + } + + /** + * Actor Function to create a Snippet + * + * @param string $snippetKey + * @param array $elements + * @param string $locale + * + * @return null|Snippet + */ + public function haveASnippetDocument($snippetKey, $elements = [], $locale = 'en') + { + $snippet = $this->generateSnippetDocument($snippetKey, $elements, $locale); + + try { + $snippet->save(); + } catch (\Exception $e) { + \Codeception\Util\Debug::debug(sprintf('[MEMBERS ERROR] error while saving document snippet. message was: ' . $e->getMessage())); + } + + $this->assertInstanceOf(Snippet::class, $snippet); + + return $snippet; + } + + /** + * Actor Function to create a mail document for given type + * + * @param $type + * @param array $mailParams + * @param string $locale + * + * @return Email + */ + public function haveAEmailDocumentForType($type, array $mailParams = [], $locale = 'en') + { + $emailDocument = $mailTemplate = $this->generateEmailDocument(sprintf('email-%s', $type), $mailParams, $locale); + $this->assertInstanceOf(Email::class, $emailDocument); + + return $emailDocument; + } + + /** + * Actor function to generate a dummy asset file. + * + * @param $fileName + * @param int $fileSizeInMb Mb + */ + public function haveFile($fileName, $fileSizeInMb = 1) + { + FileGeneratorHelper::generateDummyFile($fileName, $fileSizeInMb); + } + + /** + * Actor function to see a generated dummy file in download directory. + * + * @param $fileName + */ + public function seeDownload($fileName) + { + $supportDir = FileGeneratorHelper::getDownloadPath(); + $filePath = $supportDir . $fileName; + + $this->assertTrue(is_file($filePath)); + } + + /** + * Actor Function to place a members area on a document + * + * @param Page $document + * @param null|Page $redirectAfterSuccessDocument + * @param null|Snippet $loginSnippet + * @param bool $hideAreaAfterLogin + */ + public function seeAMembersAreaElementPlacedOnDocument(Page $document, $redirectAfterSuccessDocument = null, $loginSnippet = null, $hideAreaAfterLogin = false) + { + $areaElement = $this->createMembersArea($redirectAfterSuccessDocument, $loginSnippet, $hideAreaAfterLogin); + $document->setElements($areaElement); + + try { + $document->save(); + } catch (\Exception $e) { + \Codeception\Util\Debug::debug(sprintf('[MEMBERS ERROR] error while saving document. message was: ' . $e->getMessage())); + } + + $this->assertCount(count($areaElement), $document->getElements()); + } + + /** + * Actor Function to see if given email has been sent + * + * @param Email $email + */ + public function seeEmailIsSent(Email $email) + { + $this->assertInstanceOf(Email::class, $email); + + $foundEmails = $this->getEmailsFromDocumentIds([$email->getId()]); + $this->assertEquals(1, count($foundEmails)); + } + + /** + * Actor Function to see if an email has been sent to admin + * + * @param Email $email + */ + public function seeEmailIsNotSent(Email $email) + { + $this->assertInstanceOf(Email::class, $email); + + $foundEmails = $this->getEmailsFromDocumentIds([$email->getId()]); + $this->assertEquals(0, count($foundEmails)); + } + + /** + * Actor Function to see if admin email contains given properties + * + * @param Email $mail + * @param array $properties + */ + public function seePropertiesInEmail(Email $mail, array $properties) + { + $this->assertInstanceOf(Email::class, $mail); + + $foundEmails = $this->getEmailsFromDocumentIds([$mail->getId()]); + $this->assertGreaterThan(0, count($foundEmails)); + + $serializer = $this->getSerializer(); + + foreach ($foundEmails as $email) { + $params = $serializer->decode($email->getParams(), 'json', ['json_decode_associative' => true]); + foreach ($properties as $propertyKey => $propertyValue) { + $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)); + } + + $data = $params[$key]; + $this->assertEquals($propertyValue, $data['data']['value']); + } + } + } + + /** + * Actor Function to see if admin email contains given properties + * + * @param Email $mail + * @param array $properties + */ + public function seePropertyKeysInEmail(Email $mail, array $properties) + { + $this->assertInstanceOf(Email::class, $mail); + + $foundEmails = $this->getEmailsFromDocumentIds([$mail->getId()]); + $this->assertGreaterThan(0, count($foundEmails)); + + $serializer = $this->getSerializer(); + + foreach ($foundEmails as $email) { + $params = $serializer->decode($email->getParams(), 'json', ['json_decode_associative' => true]); + foreach ($properties as $propertyKey) { + $key = array_search($propertyKey, array_column($params, 'key')); + $this->assertNotSame(false, $key); + } + } + } + + /** + * Actor Function to see if admin email not contains given properties + * + * @param Email $mail + * @param array $properties + */ + public function cantSeePropertyKeysInEmail(Email $mail, array $properties) + { + $this->assertInstanceOf(Email::class, $mail); + + $foundEmails = $this->getEmailsFromDocumentIds([$mail->getId()]); + $this->assertGreaterThan(0, count($foundEmails)); + + $serializer = $this->getSerializer(); + + foreach ($foundEmails as $email) { + $params = $serializer->decode($email->getParams(), 'json', ['json_decode_associative' => true]); + foreach ($properties as $propertyKey) { + $this->assertFalse( + array_search( + $propertyKey, + array_column($params, 'key')), + sprintf('Failed asserting that search for "%s" is false.', $propertyKey) + ); + } + } + } + + /** + * Actor Function to see rendered body text in given email + * + * @param Email $mail + * @param string $string + */ + public function seeInRenderedEmailBody(Email $mail, string $string) + { + $this->assertInstanceOf(Email::class, $mail); + + $foundEmails = $this->getEmailsFromDocumentIds([$mail->getId()]); + $this->assertGreaterThan(0, count($foundEmails)); + + $serializer = $this->getSerializer(); + + foreach ($foundEmails as $email) { + $params = $serializer->decode($email->getParams(), 'json', ['json_decode_associative' => true]); + + $bodyKey = array_search('body', array_column($params, 'key')); + $this->assertNotSame(false, $bodyKey); + + $data = $params[$bodyKey]; + $this->assertContains($string, $data['data']['value']); + } + } + + /** + * Actor Function to see if a key has been stored in admin translations + * + * @param string $key + * + */ + public function seeKeyInFrontendTranslations(string $key) + { + /** @var Translator $translator */ + $translator = \Pimcore::getContainer()->get('pimcore.translator'); + $this->assertTrue($translator->getCatalogue()->has($key)); + } + + /** + * Actor Function to generate a single static route. + * + * @param string $name + * + * @return Staticroute + */ + public function haveAStaticRoute(string $name = 'test_route') + { + $data = [ + 'id' => 1, + 'name' => $name, + 'pattern' => '/(\\w+)\\/members-test-route\\/(\\d+)$/', + 'reverse' => '/%_locale/members-test-route/%object_id', + 'module' => 'AppBundle', + 'controller' => '@AppBundle\\Controller\\DefaultController', + 'action' => 'staticRoute', + 'variables' => '_locale,object_id', + 'defaults' => null, + 'siteId' => [], + 'priority' => 0, + 'legacy' => false, + 'creationDate' => 1545383519, + 'modificationDate' => 1545383619 + ]; + + $route = new Staticroute(); + $route->setValues($data); + $route->save(); + + $this->assertInstanceOf(Staticroute::class, $route); + + return $route; + } + + /** + * Actor Function to generate a pimcore class from json definition file. + * + * @param string $name + * + * @throws \Codeception\Exception\ModuleException + * @return ClassDefinition + */ + public function haveAPimcoreClass(string $name = 'TestClass') + { + $cm = $this->getClassManager(); + + $bundleClass = getenv('DACHCOM_BUNDLE_HOME'); + $path = $bundleClass . '/etc/config/bundle/pimcore'; + + $class = $cm->setupClass($name, sprintf('%s/%s.json', $path, $name)); + $this->assertInstanceOf(ClassDefinition::class, $class); + + return $class; + } + + /** + * API Function to get sent email ids from given document ids + * + * @public to allow usage from other modules + * + * @param array $documentIds + * + * @return Log[] + */ + public function getEmailsFromDocumentIds(array $documentIds) + { + $emailLogs = new Log\Listing(); + $emailLogs->addConditionParam(sprintf('documentId IN (%s)', implode(',', $documentIds))); + + return $emailLogs->load(); + } + + /** + * API Function to get pimcore serializer + * + * @public to allow usage from other modules + * @return Serializer + * + */ + public function getSerializer() + { + $serializer = null; + + try { + $serializer = $this->getContainer()->get('pimcore_admin.serializer'); + } catch (\Exception $e) { + \Codeception\Util\Debug::debug(sprintf('[MEMBERS ERROR] error while getting pimcore admin serializer. message was: ' . $e->getMessage())); + } + + $this->assertInstanceOf(Serializer::class, $serializer); + + return $serializer; + } + + /** + * API Function to create a Snippet + * + * @param $snippetKey + * @param array $elements + * @param string $locale + * + * @return null|Snippet + */ + protected function generateSnippetDocument($snippetKey, $elements = [], $locale = 'en') + { + $document = new Snippet(); + $document->setController('default'); + $document->setAction('snippet'); + $document->setType('snippet'); + $document->setElements($elements); + $document->setParentId(1); + $document->setUserOwner(1); + $document->setUserModification(1); + $document->setCreationDate(time()); + $document->setKey($snippetKey); + $document->setProperty('language', 'text', $locale, false, 1); + $document->setPublished(true); + + return $document; + + } + + /** + * API Function to create a page document + * + * @param string $key + * @param null|string $action + * @param null|string $controller + * @param string $locale + * + * @return Page + */ + protected function generatePageDocument($key = 'members-test', $action = null, $controller = null, $locale = 'en') + { + $action = is_null($action) ? 'default' : $action; + $controller = is_null($controller) ? '@AppBundle\Controller\DefaultController' : $controller; + + $document = TestHelper::createEmptyDocumentPage('', false); + $document->setController($controller); + $document->setAction($action); + $document->setKey($key); + $document->setProperty('language', 'text', $locale, false, 1); + + return $document; + } + + /** + * API Function to create a email document + * + * @param string $key + * @param array $params + * + * @return null|Email + */ + protected function generateEmailDocument($key = 'members-test-email', array $params = []) + { + $documentKey = uniqid(sprintf('%s-', $key)); + + $document = new Email(); + $document->setType('email'); + $document->setParentId(1); + $document->setUserOwner(1); + $document->setUserModification(1); + $document->setCreationDate(time()); + $document->setModule('MembersBundle'); + $document->setController('Email'); + $document->setAction('email'); + $document->setKey($documentKey); + + $to = 'recpient@test.org'; + if (isset($params['to'])) { + $to = $params['to']; + } + + $subject = sprintf('MEMBERS EMAIL %s', $documentKey); + if (isset($params['subject'])) { + $subject = $params['subject']; + } + + $document->setTo($to); + $document->setSubject($subject); + + if (isset($params['replyTo'])) { + $document->setReplyTo($params['replyTo']); + } + + if (isset($params['cc'])) { + $document->setCc($params['cc']); + } + + if (isset($params['bcc'])) { + $document->setBcc($params['bcc']); + } + + if (isset($params['from'])) { + $document->setFrom($params['from']); + } + + if (isset($params['properties'])) { + $document->setProperties($params['properties']); + } + + try { + $document->save(); + } catch (\Exception $e) { + \Codeception\Util\Debug::debug(sprintf('[MEMBERS ERROR] error while creating email. message was: ' . $e->getMessage())); + return null; + } + + return $document; + } + + /** + * API Function to create a members area element. + * + * @param null|Page $redirectAfterSuccessDocument + * @param null|Snippet $loginSnippet + * @param bool $hideAreaAfterLogin + * + * @return array + */ + protected function createMembersArea($redirectAfterSuccessDocument = null, $loginSnippet = null, $hideAreaAfterLogin = false) + { + $blockArea = new Areablock(); + $blockArea->setName(MembersHelper::AREA_TEST_NAMESPACE); + + $redirectAfterSuccess = null; + if ($redirectAfterSuccessDocument instanceof Page) { + $redirectAfterSuccess = new Href(); + $redirectAfterSuccess->setName(sprintf('%s:1.redirectAfterSuccess', MembersHelper::AREA_TEST_NAMESPACE)); + $data = [ + 'id' => $redirectAfterSuccessDocument->getId(), + 'type' => 'document', + 'subtype' => $redirectAfterSuccessDocument->getType() + ]; + $redirectAfterSuccess->setDataFromEditmode($data); + } + + $hideWhenLoggedIn = new Checkbox(); + $hideWhenLoggedIn->setName(sprintf('%s:1.hideWhenLoggedIn', MembersHelper::AREA_TEST_NAMESPACE)); + $hideWhenLoggedIn->setDataFromEditmode($hideAreaAfterLogin); + + $showSnippedWhenLoggedIn = null; + if ($loginSnippet instanceof Snippet) { + $showSnippedWhenLoggedIn = new Href(); + $showSnippedWhenLoggedIn->setName(sprintf('%s:1.showSnippedWhenLoggedIn', MembersHelper::AREA_TEST_NAMESPACE)); + + $data2 = [ + 'id' => $loginSnippet->getId(), + 'type' => 'document', + 'subtype' => $loginSnippet->getType() + ]; + + $showSnippedWhenLoggedIn->setDataFromEditmode($data2); + } + + $blockArea->setDataFromEditmode([ + [ + 'key' => '1', + 'type' => 'members_login', + 'hidden' => false + ] + ]); + + $data = [ + sprintf('%s', MembersHelper::AREA_TEST_NAMESPACE) => $blockArea, + sprintf('%s:1.hideWhenLoggedIn', MembersHelper::AREA_TEST_NAMESPACE) => $hideWhenLoggedIn + ]; + + if ($redirectAfterSuccess !== null) { + $data[sprintf('%s:1.redirectAfterSuccess', MembersHelper::AREA_TEST_NAMESPACE)] = $redirectAfterSuccess; + } + + if ($showSnippedWhenLoggedIn !== null) { + $data[sprintf('%s:1.showSnippedWhenLoggedIn', MembersHelper::AREA_TEST_NAMESPACE)] = $showSnippedWhenLoggedIn; + } + + return $data; + } + + /** + * @return Container + * @throws \Codeception\Exception\ModuleException + */ + protected function getContainer() + { + return $this->getModule('\\' . PimcoreCore::class)->getContainer(); + } + + /** + * @return Module|ClassManager + * @throws \Codeception\Exception\ModuleException + */ + protected function getClassManager() + { + return $this->getModule('\\' . ClassManager::class); + } +} diff --git a/tests/_support/Helper/PimcoreBundleCore.php b/tests/_support/Helper/PimcoreBundleCore.php new file mode 100644 index 00000000..7b26a25a --- /dev/null +++ b/tests/_support/Helper/PimcoreBundleCore.php @@ -0,0 +1,73 @@ +config = array_merge($this->config, [ + 'run_installer' => false + ]); + + parent::__construct($moduleContainer, $config); + } + + /** + * @param array $settings + * + * @throws \Codeception\Exception\ModuleException + */ + public function _beforeSuite($settings = []) + { + parent::_beforeSuite($settings); + + if ($this->config['run_installer'] === true) { + $this->installBundle($settings); + } + } + + /** + * @param $settings + * + * @return string|void + * @throws \Codeception\Exception\ModuleException + * @throws \Exception + */ + private function installBundle($settings) + { + /** @var PimcoreCore $pimcoreModule */ + $pimcoreModule = $this->getModule('\\' . PimcoreCore::class); + + $bundleName = getenv('DACHCOM_BUNDLE_NAME'); + $installerClass = getenv('DACHCOM_BUNDLE_INSTALLER_CLASS'); + + if ($installerClass === false) { + return; + } + + $this->debug(sprintf('[%s] Running installer...', strtoupper($bundleName))); + + if ($pimcoreModule->_getContainer()) { + $pimcoreModule->getKernel()->reboot($pimcoreModule->getKernel()->getCacheDir()); + } + + // install dachcom bundle + $installer = $pimcoreModule->getContainer()->get($installerClass); + $installer->install(); + + // install members classes + $cmd = sprintf('%s %s/bin/console members:install:class --no-interaction --env=test', Console::getExecutable('php'), PIMCORE_PROJECT_ROOT); + Console::exec($cmd); + + \Pimcore::collectGarbage(); + + } +} diff --git a/tests/_support/Helper/PimcoreCore.php b/tests/_support/Helper/PimcoreCore.php new file mode 100644 index 00000000..fe30107b --- /dev/null +++ b/tests/_support/Helper/PimcoreCore.php @@ -0,0 +1,163 @@ +config = array_merge($this->config, [ + // set specific configuration file for suite + 'configuration_file' => null + ]); + + parent::__construct($moduleContainer, $config); + } + + /** + * @inheritDoc + */ + public function _after(\Codeception\TestInterface $test) + { + parent::_after($test); + + // config has changed, we need to restore default config before starting a new test! + if ($this->kernelHasCustomConfig === true) { + $this->clearCache(); + $this->bootKernelWithConfiguration(null); + $this->kernelHasCustomConfig = false; + } + } + + /** + * @inheritdoc + */ + public function _afterSuite() + { + $this->clearCache(); + parent::_afterSuite(); + } + + /** + * @inheritdoc + */ + public function _initialize() + { + $this->setPimcoreEnvironment($this->config['environment']); + $this->initializeKernel(); + $this->setupDbConnection(); + $this->setPimcoreCacheAvailability('disabled'); + } + + /** + * @inheritdoc + */ + protected function initializeKernel() + { + $maxNestingLevel = 200; // Symfony may have very long nesting level + $xdebugMaxLevelKey = 'xdebug.max_nesting_level'; + if (ini_get($xdebugMaxLevelKey) < $maxNestingLevel) { + ini_set($xdebugMaxLevelKey, $maxNestingLevel); + } + + $configFile = null; + if ($this->config['configuration_file'] !== null) { + $configFile = $this->config['configuration_file']; + } + + $this->bootKernelWithConfiguration($configFile); + $this->setupPimcoreDirectories(); + } + + /** + * @param $configuration + */ + protected function bootKernelWithConfiguration($configuration) + { + if ($configuration === null) { + $configuration = 'config_default.yml'; + } + + putenv('DACHCOM_BUNDLE_CONFIG_FILE=' . $configuration); + + $this->kernel = require __DIR__ . '/../../kernelBuilder.php'; + $this->getKernel()->boot(); + + $this->client = new SymfonyConnector($this->kernel, $this->persistentServices, $this->config['rebootable_client']); + + if ($this->config['cache_router'] === true) { + $this->persistService('router', true); + } + + // dispatch kernel booted event - will be used from services which need to reset state between tests + $this->kernel->getContainer()->get('event_dispatcher')->dispatch(TestEvents::KERNEL_BOOTED); + } + + /** + * @param bool $force + */ + protected function clearCache($force = true) + { + $fileSystem = new Filesystem(); + + try { + $fileSystem->remove(PIMCORE_PROJECT_ROOT . '/var/cache'); + $fileSystem->mkdir(PIMCORE_PROJECT_ROOT . '/var/cache'); + } catch (\Exception $e) { + //try again later if "directory not empty" error occurs. + if ($force === true) { + sleep(1); + $this->clearCache(false); + } + } + } + + /** + * @param $env + */ + protected function setPimcoreEnvironment($env) + { + Config::setEnvironment($env); + } + + /** + * @param string $state + */ + protected function setPimcoreCacheAvailability($state = 'disabled') + { + if ($state === 'disabled') { + Cache::disable(); + } else { + Cache::enable(); + } + } + + /** + * Actor Function to boot symfony with a specific bundle configuration + * + * @param string $configuration + */ + public function haveABootedSymfonyConfiguration(string $configuration) + { + $this->kernelHasCustomConfig = true; + $this->clearCache(); + $this->bootKernelWithConfiguration($configuration); + } +} + diff --git a/tests/_support/Helper/PimcoreUser.php b/tests/_support/Helper/PimcoreUser.php new file mode 100644 index 00000000..888942d0 --- /dev/null +++ b/tests/_support/Helper/PimcoreUser.php @@ -0,0 +1,125 @@ +createUser($username, false); + $this->assertInstanceOf(User::class, $user); + + return $user; + } + + /** + * Actor Function to create a Admin User + * + * @param $username + * + * @return User + */ + public function haveAUserWithAdminRights($username) + { + $user = $this->createUser($username, true); + $this->assertInstanceOf(User::class, $user); + + return $user; + } + + /** + * API Function to get a User + * + * @param string $username + * + * @return User + */ + public function getUser($username) + { + if (isset($this->users[$username])) { + return $this->users[$username]; + } + + throw new \InvalidArgumentException(sprintf('User %s does not exist', $username)); + } + + /** + * API Function to create a User + * + * @param string $username + * @param bool $admin + * + * @return null|User|User\AbstractUser + */ + protected function createUser($username, $admin = true) + { + if (!TestHelper::supportsDbTests()) { + $this->debug(sprintf('[PIMCORE USER MODULE] Not initializing user %s as DB is not connected', $username)); + return null; + } else { + $this->debug(sprintf('[PIMCORE USER MODULE] Initializing user %s', $username)); + } + + $password = $username; + + $user = null; + + try { + $user = User::getByName($username); + } catch (\Exception $e) { + // fail silently + } + + if ($user instanceof User) { + return $user; + } + + $this->debug(sprintf('[PIMCORE USER MODULE] Creating user %s', $username)); + + $pass = null; + + try { + $pass = Authentication::getPasswordHash($username, $password); + } catch (\Exception $e) { + // fail silently. + } + + $user = User::create([ + 'parentId' => 0, + 'username' => $username, + 'password' => $pass, + 'active' => true, + 'admin' => $admin + ]); + + $this->users[$user->getName()] = $user; + + return $user; + } +} diff --git a/tests/_support/Helper/Unit.php b/tests/_support/Helper/Unit.php new file mode 100644 index 00000000..c698ec26 --- /dev/null +++ b/tests/_support/Helper/Unit.php @@ -0,0 +1,16 @@ +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(MembersHelper::DEFAULT_FEU_EMAIL); + $userObject->setUserName(MembersHelper::DEFAULT_FEU_USERNAME); + $userObject->setPlainPassword(MembersHelper::DEFAULT_FEU_PASSWORD); + $userObject->setPublished($published); + + $user = $userManager->updateUser($userObject); + + if (count($groups) > 0) { + $user->setGroups($groups); + $userManager->updateUser($user); + } + + return $user; + } + + protected function createUserGroup() + { + $group = new DataObject\MembersGroup(); + $group->setKey('group-1'); + $group->setPublished(true); + $group->setParent(DataObject::getByPath('/')); + $group->save(); + + return $group; + } + + protected function createRestrictedDocument($groups = []) + { + $document = TestHelper::createEmptyDocumentPage('restricted-document'); + + if (count($groups) > 0) { + $restriction = new Restriction(); + $restriction->setTargetId($document->getId()); + $restriction->setCtype('page'); + + $restriction->setInherit(false); + $restriction->setIsInherited(false); + $restriction->setRelatedGroups($groups); + $restriction->save(); + } + + return $document; + + } + + /** + * @return \Symfony\Component\DependencyInjection\ContainerInterface + * @throws \Codeception\Exception\ModuleException + */ + protected function getContainer() + { + return $this->getPimcoreBundle()->getContainer(); + } + + /** + * @return PimcoreCore + * @throws \Codeception\Exception\ModuleException + */ + protected function getPimcoreBundle() + { + return $this->getModule('\\' . PimcoreCore::class); + } +} diff --git a/tests/_support/Test/TestGroup.php b/tests/_support/Test/TestGroup.php new file mode 100644 index 00000000..c1452307 --- /dev/null +++ b/tests/_support/Test/TestGroup.php @@ -0,0 +1,10 @@ +exists($dataDir . 'generated')) { + $fs->mkdir($dataDir . 'generated'); + } + + if (!$fs->exists($dataDir . 'downloads')) { + $fs->mkdir($dataDir . 'downloads'); + } + } + + /** + * @return string + */ + public static function getStoragePath() + { + $dataDir = codecept_data_dir() . 'generated' . DIRECTORY_SEPARATOR; + return $dataDir; + } + + /** + * @return string + */ + public static function getDownloadPath() + { + $dataDir = codecept_data_dir() . 'downloads' . DIRECTORY_SEPARATOR; + return $dataDir; + } + + public static function cleanUp() + { + $finder = new Finder(); + $fs = new Filesystem(); + + $dataDir = self::getStoragePath(); + if ($fs->exists($dataDir)) { + $fs->remove($finder->ignoreDotFiles(true)->in($dataDir)); + } + + $downloadDir = self::getDownloadPath(); + if ($fs->exists($downloadDir)) { + $fs->remove($finder->ignoreDotFiles(true)->in($downloadDir)); + } + } +} diff --git a/tests/_support/Util/MembersHelper.php b/tests/_support/Util/MembersHelper.php new file mode 100644 index 00000000..194c5f7a --- /dev/null +++ b/tests/_support/Util/MembersHelper.php @@ -0,0 +1,55 @@ +exec('TRUNCATE TABLE members_restrictions'); + $db->exec('TRUNCATE TABLE members_group_relations'); + } + + /** + * @param string $name + * @param string $type + * @param array $options + * @param null $data + * + * @return string + */ + public static function generateEditableConfiguration(string $name, string $type, array $options, $data = null) + { + $dotSuffix = VersionHelper::pimcoreVersionIsGreaterOrEqualThan('5.5.0') ? '_' : '.'; + $colonSuffix = VersionHelper::pimcoreVersionIsGreaterOrEqualThan('5.5.0') ? '_' : ':'; + $prettyJson = VersionHelper::pimcoreVersionIsGreaterOrEqualThan('5.5.4'); + + $editableConfig = [ + 'id' => sprintf('pimcore_editable_%s%s1%s%s', self::AREA_TEST_NAMESPACE, $colonSuffix, $dotSuffix, $name), + 'name' => sprintf('%s:1.%s', self::AREA_TEST_NAMESPACE, $name), + 'realName' => $name, + 'options' => $options, + 'data' => $data, + 'type' => $type, + 'inherited' => false, + ]; + + $data = sprintf('editableConfigurations.push(%s);', json_encode($editableConfig, ($prettyJson ? JSON_PRETTY_PRINT : JSON_ERROR_NONE))); + + return $data; + } + + public static function reCreateMembersStructure() + { + $installer = \Pimcore::getContainer()->get(Install::class); + $installer->initializeFreshSetup(); + } +} diff --git a/tests/_support/Util/VersionHelper.php b/tests/_support/Util/VersionHelper.php new file mode 100644 index 00000000..0af2ebac --- /dev/null +++ b/tests/_support/Util/VersionHelper.php @@ -0,0 +1,64 @@ +'); + } + + /** + * @param string $version + * + * @return mixed + */ + public static function pimcoreVersionIsGreaterOrEqualThan(string $version) + { + return version_compare(self::getPimcoreVersion(), $version, '>='); + } + + /** + * @param string $version + * + * @return mixed + */ + public static function pimcoreVersionIsLowerThan(string $version) + { + return version_compare(self::getPimcoreVersion(), $version, '<'); + } + + /** + * @param string $version + * + * @return mixed + */ + public static function pimcoreVersionIsLowerOrEqualThan(string $version) + { + return version_compare(self::getPimcoreVersion(), $version, '<='); + } + + /** + * @return string + */ + private static function getPimcoreVersion() + { + return preg_replace('/[^0-9.]/', '', \Pimcore\Version::getVersion()); + } +} diff --git a/tests/bundle_configuration b/tests/bundle_configuration new file mode 100755 index 00000000..67014910 --- /dev/null +++ b/tests/bundle_configuration @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +export DACHCOM_BUNDLE_HOME=$TRAVIS_BUILD_DIR +export DACHCOM_BUNDLE_NAME="Members" +export DACHCOM_BUNDLE_REPO_NAME="members" +export DACHCOM_BUNDLE_COMMIT=$TRAVIS_COMMIT +export DACHCOM_BUNDLE_BRANCH=$TRAVIS_BRANCH + +export DACHCOM_BUNDLE_CLASS='MembersBundle\MembersBundle' +export DACHCOM_BUNDLE_INSTALLER_CLASS='MembersBundle\Tool\Install' + +declare -A DACHCOM_INSTALL_CONFIG_FILES=( + # system files + ["$DACHCOM_BUNDLE_HOME/etc/config/bundle/extensions.template.php"]="var/config/extensions.php" + ["$DACHCOM_BUNDLE_HOME/etc/config/bundle/system.template.php"]="var/config/system.php" + ["$DACHCOM_BUNDLE_HOME/etc/config/bundle/appKernel"]="app/AppKernel.php" + # template files + ["$DACHCOM_BUNDLE_HOME/etc/config/bundle/template/controller/DefaultController"]="src/AppBundle/Controller/DefaultController.php" + ["$DACHCOM_BUNDLE_HOME/etc/config/bundle/template/views/default"]="app/Resources/views/Default/default.html.twig" + ["$DACHCOM_BUNDLE_HOME/etc/config/bundle/template/views/snippet"]="app/Resources/views/Default/snippet.html.twig" + ["$DACHCOM_BUNDLE_HOME/etc/config/bundle/template/views/staticRoute"]="app/Resources/views/Default/staticRoute.html.twig" +) \ No newline at end of file diff --git a/tests/bundle_tests/_bootstrap.php b/tests/bundle_tests/_bootstrap.php new file mode 100644 index 00000000..8af2ac86 --- /dev/null +++ b/tests/bundle_tests/_bootstrap.php @@ -0,0 +1,21 @@ +haveAPageDocument('members-area-test'); + $I->seeAMembersAreaElementPlacedOnDocument($document); + + $I->amOnPage('/members-area-test'); + $I->seeElement('div.members.login.area'); + $I->seeElement('form[class="members_user_login"]'); + $I->seeElement('form[class="members_user_login"] input[type="text"][id="_username"]'); + $I->seeElement('form[class="members_user_login"] input[type="password"][id="_password"]'); + $I->seeElement('form[class="members_user_login"] input[type="checkbox"][id="_remember_me"]'); + $I->seeElement('form[class="members_user_login"] button[type="submit"][id="_submit"]'); + $I->seeElement('form[class="members_user_login"] input[type="hidden"][id="_target_path"]'); + $I->seeElement('form[class="members_user_login"] input[type="hidden"][id="_failure_path"]'); + } + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + */ + public function testLoginAreaElementWithDefaultSettingsAndInvalidCredentials(FunctionalTester $I) + { + $document = $I->haveAPageDocument('members-area-test'); + $I->seeAMembersAreaElementPlacedOnDocument($document); + + $I->amOnPage('/members-area-test'); + + $I->fillField('form[class="members_user_login"] input[type="text"][id="_username"]', MembersHelper::DEFAULT_FEU_USERNAME); + $I->fillField('form[class="members_user_login"] input[type="password"][id="_password"]', MembersHelper::DEFAULT_FEU_PASSWORD); + $I->click('Log In'); + + $I->seeANotLoggedInFrontEndUser(); + $I->see('Invalid credentials.', '.members.login.area div'); + + } + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + */ + public function testLoginAreaElementWithDefaultSettingsAndValidCredentials(FunctionalTester $I) + { + $I->haveARegisteredFrontEndUser(true); + + $document = $I->haveAPageDocument('members-area-test'); + $I->seeAMembersAreaElementPlacedOnDocument($document); + + $I->amOnPage('/members-area-test'); + $I->seeElement(sprintf('form[class="members_user_login"] input[type="hidden"][id="_target_path"][value="%s"]', $document->getFullPath())); + $I->seeElement(sprintf('form[class="members_user_login"] input[type="hidden"][id="_failure_path"][value="%s"]', $document->getFullPath())); + + $I->fillField('form[class="members_user_login"] input[type="text"][id="_username"]', MembersHelper::DEFAULT_FEU_USERNAME); + $I->fillField('form[class="members_user_login"] input[type="password"][id="_password"]', MembersHelper::DEFAULT_FEU_PASSWORD); + $I->click('Log In'); + + $I->see('logout', 'a'); + + $I->seeALoggedInFrontEndUser(); + } + + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + */ + public function testLoginAreaElementWithHiddenAreaAfterLogin(FunctionalTester $I) + { + $I->haveARegisteredFrontEndUser(true); + + $document = $I->haveAPageDocument('members-area-test'); + $I->seeAMembersAreaElementPlacedOnDocument($document, null, null, true); + + $I->amOnPage('/members-area-test'); + $I->seeElement(sprintf('form[class="members_user_login"] input[type="hidden"][id="_target_path"][value="%s"]', $document->getFullPath())); + $I->seeElement(sprintf('form[class="members_user_login"] input[type="hidden"][id="_failure_path"][value="%s"]', $document->getFullPath())); + + $I->fillField('form[class="members_user_login"] input[type="text"][id="_username"]', MembersHelper::DEFAULT_FEU_USERNAME); + $I->fillField('form[class="members_user_login"] input[type="password"][id="_password"]', MembersHelper::DEFAULT_FEU_PASSWORD); + $I->click('Log In'); + + $I->dontSee('logout', 'a'); + + $I->seeALoggedInFrontEndUser(); + } + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + */ + public function testLoginAreaElementWithRedirectToSpecificDocumentAfterSuccessfullyLogin(FunctionalTester $I) + { + $I->haveARegisteredFrontEndUser(true); + + $redirectDocument = $I->haveAPageDocument('success-document'); + $document = $I->haveAPageDocument('members-area-test'); + $I->seeAMembersAreaElementPlacedOnDocument($document, $redirectDocument); + + $I->amOnPage('/members-area-test'); + $I->seeElement(sprintf('form[class="members_user_login"] input[type="hidden"][id="_target_path"][value="%s"]', $redirectDocument->getFullPath())); + + $I->fillField('form[class="members_user_login"] input[type="text"][id="_username"]', MembersHelper::DEFAULT_FEU_USERNAME); + $I->fillField('form[class="members_user_login"] input[type="password"][id="_password"]', MembersHelper::DEFAULT_FEU_PASSWORD); + $I->click('Log In'); + + $I->seeLastRequestIsInPath($redirectDocument->getFullPath()); + } + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + */ + public function testLoginAreaElementWithSnippetAfterSuccessfullyLogin(FunctionalTester $I) + { + $I->haveARegisteredFrontEndUser(true); + + $successSnippet = $I->haveASnippetDocument('success-snippet'); + $document = $I->haveAPageDocument('members-area-test'); + $I->seeAMembersAreaElementPlacedOnDocument($document, null, $successSnippet, false); + + $I->amOnPage('/members-area-test'); + + $I->fillField('form[class="members_user_login"] input[type="text"][id="_username"]', MembersHelper::DEFAULT_FEU_USERNAME); + $I->fillField('form[class="members_user_login"] input[type="password"][id="_password"]', MembersHelper::DEFAULT_FEU_PASSWORD); + $I->click('Log In'); + + $I->seeALoggedInFrontEndUser(); + + $I->see(sprintf('snippet content with id %d', $successSnippet->getId()), '.snippet h3'); + + $I->seePropertiesInLastFragmentRequest(['user', 'redirect_uri', 'logout_uri', 'current_uri']); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/functional/Frontend/Form/ChangePasswordFormCest.php b/tests/bundle_tests/functional/Frontend/Form/ChangePasswordFormCest.php new file mode 100644 index 00000000..a092f706 --- /dev/null +++ b/tests/bundle_tests/functional/Frontend/Form/ChangePasswordFormCest.php @@ -0,0 +1,46 @@ +haveARegisteredFrontEndUser(true); + $I->amLoggedInAsFrontendUser($user); + + $I->amOnPage('/en/members/profile/change-password'); + $I->see('Current password', 'form[name="members_user_change_password_form"] label'); + $I->seeElement('form[name="members_user_change_password_form"] input[type="password"][id="members_user_change_password_form_current_password"]'); + $I->see('New password', 'form[name="members_user_change_password_form"] label'); + $I->seeElement('form[name="members_user_change_password_form"] input[type="password"][id="members_user_change_password_form_plainPassword_first"]'); + $I->see('Repeat new password', 'form[name="members_user_change_password_form"] label'); + $I->seeElement('form[name="members_user_change_password_form"] input[type="password"][id="members_user_change_password_form_plainPassword_second"]'); + $I->seeElement('form[name="members_user_change_password_form"] button[type="submit"][id="members_user_change_password_form_submit"]'); + } + + /** + * @param FunctionalTester $I + */ + public function testChangePassword(FunctionalTester $I) + { + $user = $I->haveARegisteredFrontEndUser(true); + $I->amLoggedInAsFrontendUser($user); + + $I->amOnPage('/en/members/profile/change-password'); + $I->fillField('form[name="members_user_change_password_form"] input[type="password"][id="members_user_change_password_form_current_password"]', MembersHelper::DEFAULT_FEU_PASSWORD); + $I->fillField('form[name="members_user_change_password_form"] input[type="password"][id="members_user_change_password_form_plainPassword_first"]', 'default-new-password'); + $I->fillField('form[name="members_user_change_password_form"] input[type="password"][id="members_user_change_password_form_plainPassword_second"]', 'default-new-password'); + $I->click('Change password'); + + $I->see('The password has been changed.', '.alert.flash-success'); + $I->see(sprintf('Username: %s', MembersHelper::DEFAULT_FEU_USERNAME), '.members_user_show'); + $I->see(sprintf('Email: %s', MembersHelper::DEFAULT_FEU_EMAIL), '.members_user_show'); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/functional/Frontend/Form/DeleteAccountFormCest.php b/tests/bundle_tests/functional/Frontend/Form/DeleteAccountFormCest.php new file mode 100644 index 00000000..8d5f19a7 --- /dev/null +++ b/tests/bundle_tests/functional/Frontend/Form/DeleteAccountFormCest.php @@ -0,0 +1,65 @@ +haveARegisteredFrontEndUser(true); + $I->amLoggedInAsFrontendUser($user); + + $I->amOnPage('/en/members/profile/delete-account'); + $I->see('Current password', 'form[name="members_user_delete_account_form"] label'); + $I->seeElement('form[name="members_user_delete_account_form"] input[type="password"][id="members_user_delete_account_form_current_password_first"]'); + $I->see('Repeat password', 'form[name="members_user_delete_account_form"] label'); + $I->seeElement('form[name="members_user_delete_account_form"] input[type="password"][id="members_user_delete_account_form_current_password_second"]'); + $I->see('Yes, I want to delete my account', 'form[name="members_user_delete_account_form"] label'); + $I->seeElement('form[name="members_user_delete_account_form"] input[type="checkbox"][id="members_user_delete_account_form_deleteConfirm"]'); + $I->seeElement('form[name="members_user_delete_account_form"] button[type="submit"][id="members_user_delete_account_form_submit"]'); + } + + /** + * @param FunctionalTester $I + */ + public function testDeleteAccountInvalid(FunctionalTester $I) + { + $user = $I->haveARegisteredFrontEndUser(true); + $I->amLoggedInAsFrontendUser($user); + + $I->amOnPage('/en/members/profile/delete-account'); + $I->fillField('form[name="members_user_delete_account_form"] input[type="password"][id="members_user_delete_account_form_current_password_first"]', + MembersHelper::DEFAULT_FEU_PASSWORD); + $I->fillField('form[name="members_user_delete_account_form"] input[type="password"][id="members_user_delete_account_form_current_password_second"]', + MembersHelper::DEFAULT_FEU_PASSWORD); + $I->click('Delete account'); + + $I->see('members.validation.delete_account.confirm_not_checked', '.form-error-message'); + } + + /** + * @param FunctionalTester $I + */ + public function testDeleteAccountValid(FunctionalTester $I) + { + $user = $I->haveARegisteredFrontEndUser(true); + $I->amLoggedInAsFrontendUser($user); + + $I->amOnPage('/en/members/profile/delete-account'); + $I->fillField('form[name="members_user_delete_account_form"] input[type="password"][id="members_user_delete_account_form_current_password_first"]', + MembersHelper::DEFAULT_FEU_PASSWORD); + $I->fillField('form[name="members_user_delete_account_form"] input[type="password"][id="members_user_delete_account_form_current_password_second"]', + MembersHelper::DEFAULT_FEU_PASSWORD); + $I->checkOption('input[id="members_user_delete_account_form_deleteConfirm"]'); + $I->click('Delete account'); + + $I->seeANotLoggedInFrontEndUser(); + $I->seeNoFrontendUserInStorage(); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/functional/Frontend/Form/LoginLogoutFormCest.php b/tests/bundle_tests/functional/Frontend/Form/LoginLogoutFormCest.php new file mode 100644 index 00000000..cb73dca5 --- /dev/null +++ b/tests/bundle_tests/functional/Frontend/Form/LoginLogoutFormCest.php @@ -0,0 +1,78 @@ +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->seeANotLoggedInFrontEndUser(); + } + + /** + * @param FunctionalTester $I + */ + public function testLoginWithInactiveUser(FunctionalTester $I) + { + $I->haveARegisteredFrontEndUser(false); + $this->login($I); + $I->see('Account is disabled.', 'div'); + $I->seeANotLoggedInFrontEndUser(); + } + + /** + * @param FunctionalTester $I + */ + public function testLoginWithValidUser(FunctionalTester $I) + { + $I->haveARegisteredFrontEndUser(true); + $this->login($I); + $I->seeALoggedInFrontEndUser(); + } + + /** + * @param FunctionalTester $I + */ + public function testLogout(FunctionalTester $I) + { + $I->haveARegisteredFrontEndUser(true); + $this->login($I); + $I->seeALoggedInFrontEndUser(true); + $I->amOnPage('/en/members/logout'); + $I->seeANotLoggedInFrontEndUser(); + } + + /** + * @param FunctionalTester $I + */ + private function login(FunctionalTester $I) + { + $I->amOnPage('/en/members/login'); + $I->fillField('form[class="members_user_login"] input[type="text"][name="_username"]', MembersHelper::DEFAULT_FEU_USERNAME); + $I->fillField('form[class="members_user_login"] input[type="password"][name="_password"]', MembersHelper::DEFAULT_FEU_PASSWORD); + $I->click('Log In'); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/functional/Frontend/Form/ProfileFormCest.php b/tests/bundle_tests/functional/Frontend/Form/ProfileFormCest.php new file mode 100644 index 00000000..b06166ac --- /dev/null +++ b/tests/bundle_tests/functional/Frontend/Form/ProfileFormCest.php @@ -0,0 +1,81 @@ +haveARegisteredFrontEndUser(true); + $I->amLoggedInAsFrontendUser($user); + + $I->amOnPage('/en/members/profile'); + $I->see(sprintf('Username: %s', MembersHelper::DEFAULT_FEU_USERNAME), '.members_user_show'); + $I->see(sprintf('Email: %s', MembersHelper::DEFAULT_FEU_EMAIL), '.members_user_show'); + } + + /** + * @param FunctionalTester $I + */ + public function testProfileEditForm(FunctionalTester $I) + { + $user = $I->haveARegisteredFrontEndUser(true); + $I->amLoggedInAsFrontendUser($user); + + $I->amOnPage('/en/members/profile/edit'); + $I->see('Username', 'form[name="members_user_profile_form"] label'); + $I->seeElement('form[name="members_user_profile_form"] input[type="text"][id="members_user_profile_form_username"]'); + $I->see('Email', 'form[name="members_user_profile_form"] label'); + $I->seeElement('form[name="members_user_profile_form"] input[type="email"][id="members_user_profile_form_email"]'); + $I->see('Current password', 'form[name="members_user_profile_form"] label'); + $I->seeElement('form[name="members_user_profile_form"] input[type="password"][id="members_user_profile_form_current_password"]'); + $I->seeElement('form[name="members_user_profile_form"] button[type="submit"][id="members_user_profile_form_submit"]'); + } + + /** + * @param FunctionalTester $I + */ + public function testProfileEditFormUpdateInvalid(FunctionalTester $I) + { + $user = $I->haveARegisteredFrontEndUser(true); + $I->amLoggedInAsFrontendUser($user); + + $I->amOnPage('/en/members/profile/edit'); + + $I->fillField('form[name="members_user_profile_form"] input[type="text"][id="members_user_profile_form_username"]', 'new-chuck'); + $I->fillField('form[name="members_user_profile_form"] input[type="email"][id="members_user_profile_form_email"]', 'new-test@universe.org'); + $I->fillField('form[name="members_user_profile_form"] input[type="password"][id="members_user_profile_form_current_password"]', 'wrong-password'); + $I->click('Update'); + + $I->see('members.validation.current_password.invalid', '.form-error-message'); + } + + /** + * @param FunctionalTester $I + */ + public function testProfileEditFormUpdateValid(FunctionalTester $I) + { + $newUserName = 'new-' . MembersHelper::DEFAULT_FEU_USERNAME; + $newEmail = 'new-' . MembersHelper::DEFAULT_FEU_EMAIL; + + $user = $I->haveARegisteredFrontEndUser(true); + $I->amLoggedInAsFrontendUser($user); + + $I->amOnPage('/en/members/profile/edit'); + + $I->fillField('form[name="members_user_profile_form"] input[type="text"][id="members_user_profile_form_username"]', $newUserName); + $I->fillField('form[name="members_user_profile_form"] input[type="email"][id="members_user_profile_form_email"]', $newEmail); + $I->fillField('form[name="members_user_profile_form"] input[type="password"][id="members_user_profile_form_current_password"]', MembersHelper::DEFAULT_FEU_PASSWORD); + $I->click('Update'); + + $I->see('The profile has been updated.', '.alert.flash-success'); + $I->see(sprintf('Username: %s', $newUserName), '.members_user_show'); + $I->see(sprintf('Email: %s', $newEmail), '.members_user_show'); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/functional/Frontend/Form/RegisterFormCest.php b/tests/bundle_tests/functional/Frontend/Form/RegisterFormCest.php new file mode 100644 index 00000000..0ac6f97a --- /dev/null +++ b/tests/bundle_tests/functional/Frontend/Form/RegisterFormCest.php @@ -0,0 +1,168 @@ +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) + { + $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.', MembersHelper::DEFAULT_FEU_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.', MembersHelper::DEFAULT_FEU_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(); + $I->publishAndConfirmAFrontendUser($user); + + $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(); + $I->publishAndConfirmAFrontendUser($user); + + $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-admin@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(sprintf('Congrats %s, your account is now activated.', MembersHelper::DEFAULT_FEU_USERNAME), '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 + * + * @throws \Exception + */ + public function testUserPropertiesAfterRegistration(FunctionalTester $I) + { + $this->register($I); + + $user = $I->grabOneUserAfterRegistration(); + $I->seePropertiesInFrontendUser($user, ['_user_locale']); + } + + /** + * @param FunctionalTester $I + */ + private function register(FunctionalTester $I) + { + $I->amOnPage('/en/members/register'); + $I->fillField('form[name="members_user_registration_form"] input[type="email"][id="members_user_registration_form_email"]', MembersHelper::DEFAULT_FEU_EMAIL); + $I->fillField('form[name="members_user_registration_form"] input[type="text"][id="members_user_registration_form_username"]', MembersHelper::DEFAULT_FEU_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/bundle_tests/functional/Frontend/Form/ResettingFormCest.php b/tests/bundle_tests/functional/Frontend/Form/ResettingFormCest.php new file mode 100644 index 00000000..5b34293f --- /dev/null +++ b/tests/bundle_tests/functional/Frontend/Form/ResettingFormCest.php @@ -0,0 +1,78 @@ +amOnPage('/en/members/resetting/request'); + + $I->see('Username or email address', 'form[class="members_user_resetting_request"] label'); + $I->seeElement('form[class="members_user_resetting_request"] input[type="text"][id="username"]'); + $I->seeElement('form[class="members_user_resetting_request"] button[type="submit"][id="submit"]'); + } + + /** + * @param FunctionalTester $I + */ + public function testResettingByUsername(FunctionalTester $I) + { + $user = $I->haveARegisteredFrontEndUser(true); + $this->triggerResetForm($I, $user->getUserName()); + } + + /** + * @param FunctionalTester $I + */ + public function testResettingByEmailAddress(FunctionalTester $I) + { + $user = $I->haveARegisteredFrontEndUser(true); + $this->triggerResetForm($I, $user->getEmail()); + } + + /** + * @param FunctionalTester $I + */ + private function triggerResetForm(FunctionalTester $I, $field) + { + $I->amOnPage('/en/members/resetting/request'); + + $I->fillField('form[class="members_user_resetting_request"] input[type="text"][id="username"]', $field); + $I->click('Reset password'); + + $confirmText = 'An email has been sent. It contains a link you must click to reset your password. '; + $confirmText .= 'Note: You can only request a new password once within 2 hours. '; + $confirmText .= 'If you don\'t get an email check your spam folder or try again.'; + + $I->see($confirmText, 'div p'); + + $email = Email::getByPath('/email/password-reset'); + $I->canSeeEmailIsSent($email); + $I->seePropertyKeysInEmail($email, ['user', 'confirmationUrl']); + + $confirmationLink = $I->haveConfirmationLinkInEmail($email); + + $I->amOnPage($confirmationLink); + $I->see('New password', 'form[name="members_user_resetting_form"] label'); + $I->seeElement('form[name="members_user_resetting_form"] input[type="password"][id="members_user_resetting_form_plainPassword_first"]'); + $I->see('Repeat new password', 'form[name="members_user_resetting_form"] label'); + $I->seeElement('form[name="members_user_resetting_form"] input[type="password"][id="members_user_resetting_form_plainPassword_second"]'); + $I->seeElement('form[name="members_user_resetting_form"] button[type="submit"][id="members_user_resetting_form_submit"]'); + + $I->fillField('form[name="members_user_resetting_form"] input[type="password"][id="members_user_resetting_form_plainPassword_first"]', 'new-pass'); + $I->fillField('form[name="members_user_resetting_form"] input[type="password"][id="members_user_resetting_form_plainPassword_second"]', 'new-pass'); + $I->click('Change password'); + + $I->see('The password has been reset successfully.', '.alert.flash-success'); + $I->see(sprintf('Username: %s', MembersHelper::DEFAULT_FEU_USERNAME), '.members_user_show'); + $I->see(sprintf('Email: %s', MembersHelper::DEFAULT_FEU_EMAIL), '.members_user_show'); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/functional/Restriction/AssetRestrictionCest.php b/tests/bundle_tests/functional/Restriction/AssetRestrictionCest.php new file mode 100644 index 00000000..e9379821 --- /dev/null +++ b/tests/bundle_tests/functional/Restriction/AssetRestrictionCest.php @@ -0,0 +1,91 @@ +haveAFrontendUserGroup('group-1'); + $asset = $I->haveAPimcoreAsset(); + + $I->addRestrictionToAsset($asset, [$group1->getId()]); + + $link = $I->haveASingleAssetDownloadLink($asset); + + $I->amOnPage($link); + $I->canSeePageNotFound(); + $I->canSeeInTitle('invalid hash for asset request.'); + } + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + * @throws \Exception + */ + public function testAssetDownloadWithoutAccessRights(FunctionalTester $I) + { + $group1 = $I->haveAFrontendUserGroup('group-1'); + $user = $I->haveARegisteredFrontEndUser(true); + $asset = $I->haveAPimcoreAsset(); + + $I->addRestrictionToAsset($asset, [$group1->getId()]); + $I->amLoggedInAsFrontendUser($user); + + $link = $I->haveASingleAssetDownloadLink($asset); + + $I->amOnPage($link); + $I->canSeePageNotFound(); + $I->canSeeInTitle('invalid hash for asset request.'); + } + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + * @throws \Exception + */ + public function testAssetDownloadWithAuthorisation(FunctionalTester $I) + { + $group1 = $I->haveAFrontendUserGroup('group-1'); + $user = $I->haveARegisteredFrontEndUser(true, [$group1]); + $asset = $I->haveAPimcoreAsset(); + + $I->addRestrictionToAsset($asset, [$group1->getId()]); + $I->amLoggedInAsFrontendUser($user); + + $link = $I->haveASingleAssetDownloadLink($asset); + + $I->seeDownloadLink($asset, $link); + } + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + * @throws \Exception + */ + public function testMultipleAssetDownloadWithAuthorisation(FunctionalTester $I) + { + $group1 = $I->haveAFrontendUserGroup('group-1'); + $user = $I->haveARegisteredFrontEndUser(true, [$group1]); + $asset1 = $I->haveAPimcoreAsset('restricted-asset-1'); + $asset2 = $I->haveAPimcoreAsset('restricted-asset-2'); + + $I->addRestrictionToAsset($asset1, [$group1->getId()]); + $I->addRestrictionToAsset($asset2, [$group1->getId()]); + $I->amLoggedInAsFrontendUser($user); + + $link = $I->haveAMultipleAssetDownloadLink([['asset' => $asset1], ['asset' => $asset2]]); + + $I->seeDownloadLinkZip('package.zip', $link); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/functional/Restriction/DocumentRestrictionCest.php b/tests/bundle_tests/functional/Restriction/DocumentRestrictionCest.php new file mode 100644 index 00000000..a1642104 --- /dev/null +++ b/tests/bundle_tests/functional/Restriction/DocumentRestrictionCest.php @@ -0,0 +1,62 @@ +haveAFrontendUserGroup('group-1'); + $user = $I->haveARegisteredFrontEndUser(true); + $document = $I->haveAPimcoreDocument('document-1'); + + $I->addRestrictionToDocument($document, [$group1->getId()]); + $I->amOnPage($document->getFullPath()); + $I->seeCurrentUrlEquals('/en/members/login'); + } + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + * @throws \Exception + */ + public function testDocumentRestrictionWithoutAccessRights(FunctionalTester $I) + { + $group1 = $I->haveAFrontendUserGroup('group-1'); + $user = $I->haveARegisteredFrontEndUser(true); + $document = $I->haveAPimcoreDocument('document-1'); + + $I->addRestrictionToDocument($document, [$group1->getId()]); + $I->amLoggedInAsFrontendUser($user); + $I->amOnPage($document->getFullPath()); + $I->see('You have no access rights to view the requested page.', '.members.refused'); + } + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + * @throws \Exception + */ + public function testDocumentRestrictionWithAuthorization(FunctionalTester $I) + { + $group1 = $I->haveAFrontendUserGroup('group-1'); + $user = $I->haveARegisteredFrontEndUser(true, [$group1]); + $document = $I->haveAPimcoreDocument('document-1'); + + $I->addRestrictionToDocument($document, [$group1->getId()]); + $I->amLoggedInAsFrontendUser($user); + $I->amOnPage($document->getFullPath()); + $I->see('Test Page for Members', 'title'); + } + +} \ No newline at end of file diff --git a/tests/bundle_tests/functional/Restriction/ObjectRestrictionCest.php b/tests/bundle_tests/functional/Restriction/ObjectRestrictionCest.php new file mode 100644 index 00000000..862b0d19 --- /dev/null +++ b/tests/bundle_tests/functional/Restriction/ObjectRestrictionCest.php @@ -0,0 +1,70 @@ +haveAPimcoreClass('TestClass'); + $staticRoute = $I->haveAStaticRoute('test_route'); + + $group1 = $I->haveAFrontendUserGroup('group-1'); + $user = $I->haveARegisteredFrontEndUser(true); + $object = $I->haveAPimcoreObject($classDefinition->getName(), 'object-1'); + + $I->addRestrictionToObject($object, [$group1->getId()]); + $I->amOnStaticRoute($staticRoute->getName(), ['_locale' => 'en', 'object_id' => $object->getId()]); + $I->seeCurrentUrlEquals('/en/members/login'); + } + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + * @throws \Exception + */ + public function testObjectRestrictionWithoutAccessRights(FunctionalTester $I) + { + $classDefinition = $I->haveAPimcoreClass('TestClass'); + $staticRoute = $I->haveAStaticRoute('test_route'); + + $group1 = $I->haveAFrontendUserGroup('group-1'); + $user = $I->haveARegisteredFrontEndUser(true); + $object = $I->haveAPimcoreObject($classDefinition->getName(), 'object-1'); + + $I->addRestrictionToObject($object, [$group1->getId()]); + $I->amLoggedInAsFrontendUser($user); + $I->amOnStaticRoute($staticRoute->getName(), ['_locale' => 'en', 'object_id' => $object->getId()]); + $I->see('You have no access rights to view the requested page.', '.members.refused'); + } + + /** + * @param FunctionalTester $I + * + * @throws \Codeception\Exception\ModuleException + * @throws \Exception + */ + public function testObjectRestrictionWithAuthorization(FunctionalTester $I) + { + $classDefinition = $I->haveAPimcoreClass('TestClass'); + $staticRoute = $I->haveAStaticRoute('test_route'); + + $group1 = $I->haveAFrontendUserGroup('group-1'); + $user = $I->haveARegisteredFrontEndUser(true, [$group1]); + $object = $I->haveAPimcoreObject($classDefinition->getName(), 'object-1'); + + $I->addRestrictionToObject($object, [$group1->getId()]); + $I->amLoggedInAsFrontendUser($user); + $I->amOnStaticRoute($staticRoute->getName(), ['_locale' => 'en', 'object_id' => $object->getId()]); + $I->see(sprintf('object id: %d', $object->getId()), '.static-route-debug'); + } +} diff --git a/tests/bundle_tests/functional/Validation/UniqueCest.php b/tests/bundle_tests/functional/Validation/UniqueCest.php new file mode 100644 index 00000000..12cb1880 --- /dev/null +++ b/tests/bundle_tests/functional/Validation/UniqueCest.php @@ -0,0 +1,38 @@ +haveARegisteredFrontEndUser(); + + $I->amOnPage('/en/members/register'); + $I->fillField('form[name="members_user_registration_form"] input[type="email"][id="members_user_registration_form_email"]', MembersHelper::DEFAULT_FEU_EMAIL); + $I->fillField('form[name="members_user_registration_form"] input[type="text"][id="members_user_registration_form_username"]', 'another-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'); + + $I->see('members.validation.email.already_used', '.form-error-message'); + } + + public function testUniqueUsername(FunctionalTester $I) + { + $I->haveARegisteredFrontEndUser(); + + $I->amOnPage('/en/members/register'); + $I->fillField('form[name="members_user_registration_form"] input[type="email"][id="members_user_registration_form_email"]', 'another-email@address.com'); + $I->fillField('form[name="members_user_registration_form"] input[type="text"][id="members_user_registration_form_username"]', MembersHelper::DEFAULT_FEU_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'); + + $I->see('members.validation.username.already_used', '.form-error-message'); + } + +} \ No newline at end of file diff --git a/tests/bundle_tests/functional/_bootstrap.php b/tests/bundle_tests/functional/_bootstrap.php new file mode 100644 index 00000000..94bf66cf --- /dev/null +++ b/tests/bundle_tests/functional/_bootstrap.php @@ -0,0 +1,2 @@ +getContainer()->get(Configuration::class); + $adminConfig = $configuration->getConfigArray(); + + $this->assertInternalType('array', $adminConfig); + $this->assertArrayHasKey('send_admin_mail_after_register', $adminConfig); + } + + /** + * @throws \Codeception\Exception\ModuleException + */ + public function testConfigSlotGetter() + { + $configuration = $this->getContainer()->get(Configuration::class); + $configSlot = $configuration->getConfig('post_register_type'); + + $this->assertInternalType('string', $configSlot); + } +} diff --git a/tests/bundle_tests/unit/EventListener/AuthenticationListenerTest.php b/tests/bundle_tests/unit/EventListener/AuthenticationListenerTest.php new file mode 100644 index 00000000..6ecf0c2f --- /dev/null +++ b/tests/bundle_tests/unit/EventListener/AuthenticationListenerTest.php @@ -0,0 +1,50 @@ +getMockBuilder('MembersBundle\Adapter\User\UserInterface')->getMock(); + $response = $this->getMockBuilder('Symfony\Component\HttpFoundation\Response')->getMock(); + $request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock(); + + $this->event = new FilterUserResponseEvent($user, $request, $response); + $this->eventDispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcher')->getMock(); + $this->eventDispatcher + ->expects($this->once()) + ->method('dispatch'); + + $loginManager = $this->getMockBuilder('MembersBundle\Manager\LoginManagerInterface')->getMock(); + $this->listener = new AuthenticationListener($loginManager, self::FIREWALL_NAME); + } + + public function testAuthenticate() + { + $this->listener->authenticate($this->event, MembersEvents::REGISTRATION_COMPLETED, $this->eventDispatcher); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/unit/EventListener/FlashListenerTest.php b/tests/bundle_tests/unit/EventListener/FlashListenerTest.php new file mode 100644 index 00000000..edcfa5bf --- /dev/null +++ b/tests/bundle_tests/unit/EventListener/FlashListenerTest.php @@ -0,0 +1,40 @@ +event = new Event(); + $flashBag = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\Flash\FlashBag')->getMock(); + $session = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\Session')->disableOriginalConstructor()->getMock(); + $session + ->expects($this->once()) + ->method('getFlashBag') + ->willReturn($flashBag); + + $translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock(); + $this->listener = new FlashListener($session, $translator); + } + + public function testAddSuccessFlash() + { + $this->listener->addSuccessFlash($this->event, MembersEvents::CHANGE_PASSWORD_COMPLETED); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/unit/Manager/ClassManagerTest.php b/tests/bundle_tests/unit/Manager/ClassManagerTest.php new file mode 100644 index 00000000..89e96272 --- /dev/null +++ b/tests/bundle_tests/unit/Manager/ClassManagerTest.php @@ -0,0 +1,55 @@ +getContainer()->get(ClassManager::class); + $groupClass = $classManager->getGroupClass(); + + $this->assertEquals(MembersGroup::class, $groupClass); + } + + /** + * @throws \Codeception\Exception\ModuleException + */ + public function testGroupListing() + { + $classManager = $this->getContainer()->get(ClassManager::class); + $groupListing = $classManager->getGroupListing(); + + $this->assertInstanceOf(MembersGroup\Listing::class, $groupListing); + } + + /** + * @throws \Codeception\Exception\ModuleException + */ + public function testUserClass() + { + $classManager = $this->getContainer()->get(ClassManager::class); + $userClass = $classManager->getUserClass(); + + $this->assertEquals(MembersUser::class, $userClass); + } + + /** + * @throws \Codeception\Exception\ModuleException + */ + public function testUserListing() + { + $classManager = $this->getContainer()->get(ClassManager::class); + $userListing = $classManager->getUserListing(); + + $this->assertInstanceOf(MembersUser\Listing::class, $userListing); + } +} diff --git a/tests/bundle_tests/unit/Manager/LoginManagerTest.php b/tests/bundle_tests/unit/Manager/LoginManagerTest.php new file mode 100644 index 00000000..98046524 --- /dev/null +++ b/tests/bundle_tests/unit/Manager/LoginManagerTest.php @@ -0,0 +1,89 @@ +createLoginManager(); + $loginManager->logInUser('main', $this->mockUser()); + } + + public function testLogInUserWithRememberMeAndRequestStack() + { + $response = $this->getMockBuilder(Response::class)->getMock(); + $loginManager = $this->createLoginManager($response); + $loginManager->logInUser('main', $this->mockUser(), $response); + } + + /** + * @param Response|null $response + * + * @return LoginManager + */ + private function createLoginManager(Response $response = null) + { + $tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock(); + $tokenStorage + ->expects($this->once()) + ->method('setToken') + ->with($this->isInstanceOf(TokenInterface::class)); + + $userChecker = $this->getMockBuilder(UserChecker::class)->getMock(); + $userChecker + ->expects($this->once()) + ->method('checkPreAuth') + ->with($this->isInstanceOf(UserInterface::class)); + + $request = $this->getMockBuilder(Request::class)->getMock(); + + $sessionStrategy = $this->getMockBuilder(SessionAuthenticationStrategyInterface::class)->getMock(); + $sessionStrategy + ->expects($this->once()) + ->method('onAuthentication') + ->with($request, $this->isInstanceOf(TokenInterface::class)); + + $requestStack = $this->getMockBuilder(RequestStack::class)->getMock(); + $requestStack + ->expects($this->once()) + ->method('getCurrentRequest') + ->will($this->returnValue($request)); + + $rememberMe = null; + if (null !== $response) { + $rememberMe = $this->getMockBuilder(RememberMeServicesInterface::class)->getMock(); + $rememberMe + ->expects($this->once()) + ->method('loginSuccess') + ->with($request, $response, $this->isInstanceOf(TokenInterface::class)); + } + + return new LoginManager($tokenStorage, $userChecker, $sessionStrategy, $requestStack, $rememberMe); + } + + /** + * @return mixed + */ + private function mockUser() + { + $user = $this->getMockBuilder(UserInterface::class)->getMock(); + $user + ->expects($this->once()) + ->method('getRoles') + ->will($this->returnValue(['ROLE_USER'])); + return $user; + } +} \ No newline at end of file diff --git a/tests/bundle_tests/unit/Manager/RestrictionManagerTest.php b/tests/bundle_tests/unit/Manager/RestrictionManagerTest.php new file mode 100644 index 00000000..fe08ad5b --- /dev/null +++ b/tests/bundle_tests/unit/Manager/RestrictionManagerTest.php @@ -0,0 +1,49 @@ +createRestrictedDocument(); + $restrictionManager = $this->getContainer()->get(RestrictionManager::class); + $restrictionGroups = $restrictionManager->getElementRestrictedGroups($document); + + $this->assertInternalType('array', $restrictionGroups); + $this->assertCount(1, $restrictionGroups); + $this->assertContains('default', $restrictionGroups); + } + + public function testGetElementRestrictedGroups() + { + $group = $this->createUserGroup(); + $document = $this->createRestrictedDocument([$group->getId()]); + + $restrictionManager = $this->getContainer()->get(RestrictionManager::class); + $restrictionGroups = $restrictionManager->getElementRestrictedGroups($document); + + $this->assertInternalType('array', $restrictionGroups); + $this->assertCount(1, $restrictionGroups); + $this->assertContains($group->getId(), $restrictionGroups); + + } + + public function testGetElementRestrictionStatus() + { + $group = $this->createUserGroup(); + $document = $this->createRestrictedDocument([$group->getId()]); + + $restrictionManager = $this->getContainer()->get(RestrictionManager::class); + $restrictionStatus = $restrictionManager->getElementRestrictionStatus($document); + + $this->assertInstanceOf(ElementRestriction::class, $restrictionStatus); + $this->assertEquals(RestrictionManager::RESTRICTION_STATE_NOT_LOGGED_IN, $restrictionStatus->getState()); + $this->assertEquals(RestrictionManager::RESTRICTION_SECTION_NOT_ALLOWED, $restrictionStatus->getSection()); + $this->assertEquals([$group->getId()], $restrictionStatus->getRestrictionGroups()); + } +} diff --git a/tests/bundle_tests/unit/Manager/UserManagerTest.php b/tests/bundle_tests/unit/Manager/UserManagerTest.php new file mode 100644 index 00000000..b49a45d2 --- /dev/null +++ b/tests/bundle_tests/unit/Manager/UserManagerTest.php @@ -0,0 +1,81 @@ +getContainer()->get(UserManager::class); + $groupClass = $userManager->getClass(); + + $this->assertEquals(MembersUser::class, $groupClass); + } + + public function testCreateNewUser() + { + $user = $this->createUser(); + $this->assertInstanceOf(UserInterface::class, $user); + + $expectedKey = \Pimcore\File::getValidFilename($user->getEmail()); + $this->assertEquals($expectedKey, $user->getKey()); + } + + public function testFindUserByEmail() + { + $this->createUser(); + $userManager = $this->getContainer()->get(UserManager::class); + + $this->assertInstanceOf(UserInterface::class, $userManager->findUserByEmail(MembersHelper::DEFAULT_FEU_EMAIL)); + } + + public function testFindUserByUsername() + { + $this->createUser(); + $userManager = $this->getContainer()->get(UserManager::class); + + $this->assertInstanceOf(UserInterface::class, $userManager->findUserByUsername(MembersHelper::DEFAULT_FEU_USERNAME)); + } + + public function testFindUserByUsernameOrEmail() + { + $this->createUser(); + $userManager = $this->getContainer()->get(UserManager::class); + + $this->assertInstanceOf(UserInterface::class, $userManager->findUserByUsernameOrEmail(MembersHelper::DEFAULT_FEU_EMAIL)); + $this->assertInstanceOf(UserInterface::class, $userManager->findUserByUsernameOrEmail(MembersHelper::DEFAULT_FEU_USERNAME)); + } + + public function testFindUserByCondition() + { + $this->createUser(); + $userManager = $this->getContainer()->get(UserManager::class); + + $this->assertInstanceOf(UserInterface::class, $userManager->findUserByCondition('email = ?', [MembersHelper::DEFAULT_FEU_EMAIL])); + } + + public function testFindPublishedUsers() + { + $this->createUser(true); + $userManager = $this->getContainer()->get(UserManager::class); + + $this->assertCount(1, $userManager->findUsers()); + } + + public function testFindUnPublishedUsers() + { + $this->createUser(false); + $userManager = $this->getContainer()->get(UserManager::class); + + $this->assertCount(0, $userManager->findUsers()); + } +} diff --git a/tests/bundle_tests/unit/Security/EmailUserProviderTest.php b/tests/bundle_tests/unit/Security/EmailUserProviderTest.php new file mode 100644 index 00000000..132332ae --- /dev/null +++ b/tests/bundle_tests/unit/Security/EmailUserProviderTest.php @@ -0,0 +1,75 @@ +userManager = $this->getMockBuilder('MembersBundle\Manager\UserManagerInterface')->getMock(); + $this->userProvider = new EmailUserProvider($this->userManager); + } + + public function testLoadUserByUsername() + { + $user = $this->getMockBuilder('MembersBundle\Adapter\User\UserInterface')->getMock(); + $this->userManager->expects($this->once()) + ->method('findUserByUsernameOrEmail') + ->with('foobar') + ->will($this->returnValue($user)); + $this->assertSame($user, $this->userProvider->loadUserByUsername('foobar')); + } + + /** + * @expectedException \Symfony\Component\Security\Core\Exception\UsernameNotFoundException + */ + public function testLoadUserByInvalidUsername() + { + $this->userManager->expects($this->once()) + ->method('findUserByUsernameOrEmail') + ->with('foobar') + ->will($this->returnValue(null)); + $this->userProvider->loadUserByUsername('foobar'); + } + + public function testRefreshUserBy() + { + $user = $this->getMockBuilder(MembersUser::class) + ->setMethods(['getId']) + ->getMock(); + $user->expects($this->once()) + ->method('getId') + ->will($this->returnValue('2')); + $refreshedUser = $this->getMockBuilder('MembersBundle\Adapter\User\UserInterface')->getMock(); + $this->userManager->expects($this->once()) + ->method('findUserByCondition') + ->with('oo_id = ?', ['2']) + ->will($this->returnValue($refreshedUser)); + $this->userManager->expects($this->atLeastOnce()) + ->method('getClass') + ->will($this->returnValue(get_class($user))); + $this->assertSame($refreshedUser, $this->userProvider->refreshUser($user)); + } + + /** + * @expectedException \Symfony\Component\Security\Core\Exception\UnsupportedUserException + */ + public function testRefreshInvalidUser() + { + $user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock(); + $this->userProvider->refreshUser($user); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/unit/Security/UserCheckerTest.php b/tests/bundle_tests/unit/Security/UserCheckerTest.php new file mode 100644 index 00000000..651c155d --- /dev/null +++ b/tests/bundle_tests/unit/Security/UserCheckerTest.php @@ -0,0 +1,80 @@ +expectException(\Symfony\Component\Security\Core\Exception\LockedException::class); + $this->expectExceptionMessage('User account is locked.'); + + $userMock = $this->getUser(false, false, false); + $checker = new UserChecker(); + $checker->checkPreAuth($userMock); + } + + public function testCheckPreAuthFailsIsPublished() + { + $this->expectException(\Symfony\Component\Security\Core\Exception\DisabledException::class); + $this->expectExceptionMessage('User account is disabled.'); + + $userMock = $this->getUser(true, false, false); + $checker = new UserChecker(); + $checker->checkPreAuth($userMock); + } + + public function testCheckPreAuthFailsIsAccountNonExpired() + { + $this->expectException(\Symfony\Component\Security\Core\Exception\AccountExpiredException::class); + $this->expectExceptionMessage('User account has expired.'); + + $userMock = $this->getUser(true, true, false); + $checker = new UserChecker(); + $checker->checkPreAuth($userMock); + } + + public function testCheckPreAuthSuccess() + { + $userMock = $this->getUser(true, true, true); + $checker = new UserChecker(); + + try { + $this->assertNull($checker->checkPreAuth($userMock)); + } catch (\Exception $ex) { + $this->fail(); + } + } + + public function testCheckPostAuthSuccess() + { + $userMock = $this->getUser(true, true, true); + $checker = new UserChecker(); + + try { + $this->assertNull($checker->checkPostAuth($userMock)); + } catch (\Exception $ex) { + $this->fail(); + } + } + + private function getUser($isAccountNonLocked, $isPublished, $isAccountNonExpired) + { + $userMock = $this->getMockBuilder(MembersUser::class)->getMock(); + $userMock + ->method('isAccountNonLocked') + ->willReturn($isAccountNonLocked); + $userMock + ->method('getPublished') + ->willReturn($isPublished); + $userMock + ->method('isAccountNonExpired') + ->willReturn($isAccountNonExpired); + + return $userMock; + } +} \ No newline at end of file diff --git a/tests/bundle_tests/unit/Security/UserProviderTest.php b/tests/bundle_tests/unit/Security/UserProviderTest.php new file mode 100644 index 00000000..639b803f --- /dev/null +++ b/tests/bundle_tests/unit/Security/UserProviderTest.php @@ -0,0 +1,111 @@ +userManager = $this->getMockBuilder('MembersBundle\Manager\UserManagerInterface')->getMock(); + $this->userProvider = new UserProvider($this->userManager); + } + + public function testLoadUserByUsername() + { + $user = $this->getMockBuilder('MembersBundle\Adapter\User\UserInterface')->getMock(); + + $this->userManager->expects($this->once()) + ->method('findUserByUsername') + ->with('foobar') + ->will($this->returnValue($user)); + + $this->assertSame($user, $this->userProvider->loadUserByUsername('foobar')); + } + + public function testLoadUserByInvalidUsername() + { + $this->userManager->expects($this->once()) + ->method('findUserByUsername') + ->with('foobar') + ->will($this->returnValue(null)); + + $this->expectException(\Symfony\Component\Security\Core\Exception\UsernameNotFoundException::class); + $this->userProvider->loadUserByUsername('foobar'); + } + + public function testRefreshUserBy() + { + $user = $this->getMockBuilder(MembersUser::class) + ->setMethods(['getId']) + ->getMock(); + + $user->expects($this->once()) + ->method('getId') + ->will($this->returnValue('2')); + + $refreshedUser = $this->getMockBuilder('MembersBundle\Adapter\User\UserInterface')->getMock(); + + $this->userManager->expects($this->once()) + ->method('findUserByCondition') + ->with('oo_id = ?', ['2']) + ->will($this->returnValue($refreshedUser)); + + $this->userManager->expects($this->atLeastOnce()) + ->method('getClass') + ->will($this->returnValue(get_class($user))); + + $this->assertSame($refreshedUser, $this->userProvider->refreshUser($user)); + } + + public function testRefreshDeleted() + { + $user = $this->getMockForAbstractClass(MembersUser::class); + + $this->userManager->expects($this->once()) + ->method('findUserByCondition') + ->will($this->returnValue(null)); + $this->userManager->expects($this->atLeastOnce()) + ->method('getClass') + ->will($this->returnValue(get_class($user))); + + $this->expectException(\Symfony\Component\Security\Core\Exception\UsernameNotFoundException::class); + $this->userProvider->refreshUser($user); + } + + public function testRefreshInvalidUser() + { + $user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock(); + $this->userManager->expects($this->any()) + ->method('getClass') + ->will($this->returnValue(get_class($user))); + + $this->expectException(\Symfony\Component\Security\Core\Exception\UnsupportedUserException::class); + $this->userProvider->refreshUser($user); + } + + public function testRefreshInvalidUserClass() + { + $user = $this->getMockBuilder(MembersUser::class)->getMock(); + $providedUser = $this->getMockBuilder('DachcomBundle\Test\Test\TestUser')->getMock(); + + $this->userManager->expects($this->atLeastOnce()) + ->method('getClass') + ->will($this->returnValue(get_class($user))); + + $this->expectException(\Symfony\Component\Security\Core\Exception\UnsupportedUserException::class); + $this->userProvider->refreshUser($providedUser); + } +} \ No newline at end of file diff --git a/tests/bundle_tests/unit/_bootstrap.php b/tests/bundle_tests/unit/_bootstrap.php new file mode 100644 index 00000000..8a885558 --- /dev/null +++ b/tests/bundle_tests/unit/_bootstrap.php @@ -0,0 +1,2 @@ +addBundle(new \AppBundle\AppBundle()); + } + + $collection->addBundle(new \Symfony\Bundle\WebServerBundle\WebServerBundle()); + } +} \ No newline at end of file diff --git a/tests/etc/config/bundle/extensions.template.php b/tests/etc/config/bundle/extensions.template.php new file mode 100644 index 00000000..376123be --- /dev/null +++ b/tests/etc/config/bundle/extensions.template.php @@ -0,0 +1,7 @@ + [ + "MembersBundle\\MembersBundle" => TRUE, + ] +]; diff --git a/tests/etc/config/bundle/pimcore/TestClass.json b/tests/etc/config/bundle/pimcore/TestClass.json new file mode 100644 index 00000000..b68151fc --- /dev/null +++ b/tests/etc/config/bundle/pimcore/TestClass.json @@ -0,0 +1,95 @@ +{ + "description": null, + "parentClass": null, + "listingParentClass": null, + "useTraits": null, + "listingUseTraits": null, + "allowInherit": false, + "allowVariants": false, + "showVariants": false, + "layoutDefinitions": { + "fieldtype": "panel", + "labelWidth": 100, + "layout": null, + "name": "pimcore_root", + "type": null, + "region": null, + "title": null, + "width": null, + "height": null, + "collapsible": false, + "collapsed": false, + "bodyStyle": null, + "datatype": "layout", + "permissions": null, + "childs": [ + { + "fieldtype": "panel", + "labelWidth": 100, + "layout": null, + "name": "Layout", + "type": null, + "region": null, + "title": "", + "width": null, + "height": null, + "collapsible": false, + "collapsed": false, + "bodyStyle": "", + "datatype": "layout", + "permissions": null, + "childs": [ + { + "fieldtype": "input", + "width": null, + "queryColumnType": "varchar", + "columnType": "varchar", + "columnLength": 190, + "phpdocType": "string", + "regex": "", + "unique": false, + "showCharCount": false, + "name": "title", + "title": "title", + "tooltip": "", + "mandatory": false, + "noteditable": false, + "index": false, + "locked": false, + "style": "", + "permissions": null, + "datatype": "data", + "relationType": false, + "invisible": false, + "visibleGridView": false, + "visibleSearch": false + } + ], + "locked": false + } + ], + "locked": false + }, + "icon": null, + "previewUrl": null, + "group": null, + "linkGeneratorReference": null, + "propertyVisibility": { + "grid": { + "id": true, + "key": false, + "path": true, + "published": true, + "modificationDate": true, + "creationDate": true + }, + "search": { + "id": true, + "key": false, + "path": true, + "published": true, + "modificationDate": true, + "creationDate": true + } + } +} \ No newline at end of file diff --git a/tests/etc/config/bundle/symfony/config_default.yml b/tests/etc/config/bundle/symfony/config_default.yml new file mode 100755 index 00000000..eca425e7 --- /dev/null +++ b/tests/etc/config/bundle/symfony/config_default.yml @@ -0,0 +1,10 @@ +members: + restriction: + enabled: true + allowed_objects: + - 'TestClass' + +services: + DachcomBundle\Test\App\Services\TestRestrictedStaticRouteListener: + tags: + - { name: kernel.event_subscriber } \ 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' diff --git a/tests/etc/config/bundle/system.template.php b/tests/etc/config/bundle/system.template.php new file mode 100755 index 00000000..5c8d594f --- /dev/null +++ b/tests/etc/config/bundle/system.template.php @@ -0,0 +1,167 @@ + [ + "timezone" => "Europe/Berlin", + "path_variable" => "", + "domain" => "localhost", + "redirect_to_maindomain" => false, + "language" => "en", + "validLanguages" => "en,de", + "fallbackLanguages" => [ + "en" => "", + "de" => "" + ], + "defaultLanguage" => "", + "loginscreencustomimage" => "", + "disableusagestatistics" => false, + "debug" => true, + "debug_ip" => "", + "http_auth" => [ + "username" => "", + "password" => "" + ], + "debug_admin_translations" => false, + "devmode" => false, + "instanceIdentifier" => "", + "show_cookie_notice" => false + ], + "database" => [ + "adapter" => "Pdo_Mysql", + "params" => [ + "host" => "localhost", + "username" => "root", + "password" => "", + "dbname" => "dachcom_bundle_test", + "port" => "3306" + ] + ], + "documents" => [ + "versions" => [ + "days" => null, + "steps" => 10 + ], + "default_controller" => "Default", + "default_action" => "default", + "error_pages" => [ + "default" => "/error" + ], + "createredirectwhenmoved" => false, + "allowtrailingslash" => "no", + "generatepreview" => true + ], + "objects" => [ + "versions" => [ + "days" => null, + "steps" => 10 + ] + ], + "assets" => [ + "versions" => [ + "days" => null, + "steps" => 10 + ], + "icc_rgb_profile" => "", + "icc_cmyk_profile" => "", + "hide_edit_image" => false, + "disable_tree_preview" => false + ], + "services" => [ + "google" => [ + "client_id" => "", + "email" => "", + "simpleapikey" => "", + "browserapikey" => "" + ] + ], + "cache" => [ + "enabled" => false, + "lifetime" => null, + "excludePatterns" => "", + "excludeCookie" => "" + ], + "outputfilters" => [ + "less" => false, + "lesscpath" => "" + ], + "webservice" => [ + "enabled" => true + ], + "httpclient" => [ + "adapter" => "Zend_Http_Client_Adapter_Socket", + "proxy_host" => "", + "proxy_port" => "", + "proxy_user" => "", + "proxy_pass" => "" + ], + "email" => [ + "sender" => [ + "name" => "pimcore", + "email" => "pimcore@example.com" + ], + "return" => [ + "name" => "pimcore", + "email" => "pimcore@example.com" + ], + "method" => "mail", + "smtp" => [ + "host" => "", + "port" => "", + "ssl" => null, + "name" => "", + "auth" => [ + "method" => "login", + "username" => "", + "password" => "" + ] + ], + "debug" => [ + "emailaddresses" => "" + ], + "bounce" => [ + "type" => "", + "maildir" => "", + "mbox" => "", + "imap" => [ + "host" => "", + "port" => "", + "username" => "", + "password" => "", + "ssl" => false + ] + ] + ], + "newsletter" => [ + "sender" => [ + "name" => "", + "email" => "" + ], + "return" => [ + "name" => "", + "email" => "" + ], + "method" => null, + "smtp" => [ + "host" => "", + "port" => "", + "ssl" => "ssl", + "name" => "", + "auth" => [ + "method" => null, + "username" => "", + "password" => null + ] + ], + "debug" => null, + "usespecific" => true + ], + "applicationlog" => [ + "mail_notification" => [ + "send_log_summary" => false, + "filter_priority" => null, + "mail_receiver" => "" + ], + "archive_treshold" => "30", + "archive_alternative_database" => "" + ] +]; diff --git a/tests/etc/config/bundle/template/controller/DefaultController b/tests/etc/config/bundle/template/controller/DefaultController new file mode 100644 index 00000000..b8635572 --- /dev/null +++ b/tests/etc/config/bundle/template/controller/DefaultController @@ -0,0 +1,27 @@ +setViewAutoRender($event->getRequest(), true, 'twig'); + } + + public function defaultAction(Request $request) + { + } + + public function snippetAction(Request $request) + { + } + + public function staticRouteAction(Request $request) + { + } +} diff --git a/tests/etc/config/bundle/template/views/default b/tests/etc/config/bundle/template/views/default new file mode 100644 index 00000000..c5cee92e --- /dev/null +++ b/tests/etc/config/bundle/template/views/default @@ -0,0 +1,14 @@ + + + + + Test Page for Members + + +
+ {% block content %} + {{ pimcore_areablock('dachcomBundleTest') }} + {% endblock %} +
+ + diff --git a/tests/etc/config/bundle/template/views/snippet b/tests/etc/config/bundle/template/views/snippet new file mode 100644 index 00000000..7c7fffe9 --- /dev/null +++ b/tests/etc/config/bundle/template/views/snippet @@ -0,0 +1,6 @@ +
+ {% block content %} +

snippet content with id {{ document.getId() }}

+ {{ pimcore_areablock('dachcomBundleTest') }} + {% endblock %} +
\ No newline at end of file diff --git a/tests/etc/config/bundle/template/views/staticRoute b/tests/etc/config/bundle/template/views/staticRoute new file mode 100644 index 00000000..74bd09fc --- /dev/null +++ b/tests/etc/config/bundle/template/views/staticRoute @@ -0,0 +1,6 @@ +
+ {% block content %} +

static route page

+
object id: {{ app.request.get('object_id') }}
+ {% endblock %} +
\ No newline at end of file diff --git a/tests/etc/config/system/config.yml b/tests/etc/config/system/config.yml new file mode 100755 index 00000000..686ce681 --- /dev/null +++ b/tests/etc/config/system/config.yml @@ -0,0 +1,14 @@ +imports: + - { resource: parameters.yml } + - { resource: security.yml } + - { resource: services.yml } + - { resource: 'local/' } + +# don't send real emails in functional tests +swiftmailer: + disable_delivery: true + +framework: + profiler: + enabled: true + collect: false \ No newline at end of file diff --git a/tests/etc/config/system/php.ini b/tests/etc/config/system/php.ini new file mode 100755 index 00000000..36357587 --- /dev/null +++ b/tests/etc/config/system/php.ini @@ -0,0 +1,8 @@ + +; extensions +;extension="memcache.so" +;extension="memcached.so" + +; custom php settings +memory_limit = 1G +date.timezone = Europe/Berlin \ No newline at end of file diff --git a/tests/etc/config/system/routing.yml b/tests/etc/config/system/routing.yml new file mode 100644 index 00000000..50005c94 --- /dev/null +++ b/tests/etc/config/system/routing.yml @@ -0,0 +1,5 @@ +_pimcore: + resource: "@PimcoreCoreBundle/Resources/config/routing.yml" + +app: + resource: '@MembersBundle/Resources/config/pimcore/routing/all.yml' \ No newline at end of file diff --git a/tests/etc/scripts/codeception b/tests/etc/scripts/codeception new file mode 100755 index 00000000..41b6c4f5 --- /dev/null +++ b/tests/etc/scripts/codeception @@ -0,0 +1,12 @@ +#!/bin/bash +set -e + +echo "START CODECEPTION TESTS FOR $DACHCOM_BUNDLE_NAME" + +CMD="vendor/bin/codecept run -c lib/$DACHCOM_BUNDLE_NAME --env travis" + +# generate json result file +CMD="$CMD --json" + +echo $CMD +eval $CMD diff --git a/tests/etc/travis/install b/tests/etc/travis/install new file mode 100755 index 00000000..849281eb --- /dev/null +++ b/tests/etc/travis/install @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +set -e + + +## include global bundle test configuration + +source $TRAVIS_BUILD_DIR/tests/bundle_configuration + + +## setup php + +phpenv config-add $DACHCOM_BUNDLE_HOME/tests/etc/config/system/php.ini + + +# Install chrome driver + +wget -c -nc --retry-connrefused --tries=0 "https://chromedriver.storage.googleapis.com/${CHROME_DRIVER_VERSION}/chromedriver_linux64.zip" -O chromedriver_linux64.zip +unzip -o -q chromedriver_linux64.zip -d $HOME + + +## setup mysql + +mysql --version +mysql -e "SET GLOBAL innodb_file_format=Barracuda;" +mysql -e "SET GLOBAL innodb_large_prefix=1;" +mysql -e "CREATE DATABASE dachcom_bundle_test CHARSET=utf8mb4;" + + +## move bundle temporarily and clean dir in order to install pimcore + +mkdir -p $DACHCOM_BUNDLE_HOME/../lib/$DACHCOM_BUNDLE_NAME +mv $DACHCOM_BUNDLE_HOME/{.[!.],}* $DACHCOM_BUNDLE_HOME/../lib/$DACHCOM_BUNDLE_NAME +rm -rf $DACHCOM_BUNDLE_HOME/{.[!.],}* + + +## clone pimcore + +git clone https://github.com/pimcore/skeleton.git $DACHCOM_BUNDLE_HOME +git checkout ${PIMCORE_SKELETON_BRANCH} $DACHCOM_BUNDLE_HOME + + +## move bundle back into lib/$DACHCOM_BUNDLE_NAME + +mv $DACHCOM_BUNDLE_HOME/../lib $DACHCOM_BUNDLE_HOME + + +## copy etc dir to root dir + +cp -r $DACHCOM_BUNDLE_HOME/lib/$DACHCOM_BUNDLE_NAME/tests/bundle_configuration $DACHCOM_BUNDLE_HOME/bundle_configuration +cp -r $DACHCOM_BUNDLE_HOME/lib/$DACHCOM_BUNDLE_NAME/tests/etc $DACHCOM_BUNDLE_HOME/etc +chmod -R +x $DACHCOM_BUNDLE_HOME/etc + + +## create download dir + +mkdir $DACHCOM_BUNDLE_HOME/lib/$DACHCOM_BUNDLE_NAME/tests/_data/downloads + + +## add config templates + +mkdir -p $DACHCOM_BUNDLE_HOME/var/config +cp $DACHCOM_BUNDLE_HOME/etc/config/system/config.yml app/config/config.yml +cp $DACHCOM_BUNDLE_HOME/etc/config/system/routing.yml app/config/routing.yml +cp app/config/parameters.example.yml app/config/parameters.yml + +for K in "${!DACHCOM_INSTALL_CONFIG_FILES[@]}" +do + cp $K ${DACHCOM_INSTALL_CONFIG_FILES[$K]}; +done + +## install composer dependencies + +COMPOSER_MEMORY_LIMIT=-1 composer install --no-scripts + +## install $DACHCOM_BUNDLE_NAME dependencies + +COMPOSER_MEMORY_LIMIT=-1 composer require symfony/phpunit-bridge:^3 dachcom-digital/$DACHCOM_BUNDLE_REPO_NAME:dev-$DACHCOM_BUNDLE_BRANCH#$DACHCOM_BUNDLE_COMMIT + + +## clear cache + +rm -rf var/cache diff --git a/tests/etc/travis/script b/tests/etc/travis/script new file mode 100755 index 00000000..e8e5168a --- /dev/null +++ b/tests/etc/travis/script @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -e + +source $TRAVIS_BUILD_DIR/bundle_configuration + +$DACHCOM_BUNDLE_HOME/etc/scripts/codeception \ No newline at end of file diff --git a/tests/kernelBuilder.php b/tests/kernelBuilder.php new file mode 100644 index 00000000..728d8563 --- /dev/null +++ b/tests/kernelBuilder.php @@ -0,0 +1,19 @@ +activatesKernelDebugMode($environment); + +if ($debug) { + Debug::enable(); + @ini_set('display_errors', 'On'); +} + +$kernel = new \DachcomBundle\Test\App\TestAppKernel($environment, $debug); + +return $kernel;