diff --git a/documentation.md b/documentation.md index a9d3f016..6c554be5 100644 --- a/documentation.md +++ b/documentation.md @@ -220,6 +220,21 @@ Authenticates user for HTTP_AUTH * `param` $password +### amOnAction + +Opens web page by action name + +``` php +amOnAction('PostController::index'); +$I->amOnAction('HomeController'); +$I->amOnAction('ArticleController', ['slug' => 'lorem-ipsum']); +``` + + * `param string` $action + * `param array` $params + + ### amOnPage Opens the page for the given relative URI. @@ -361,6 +376,20 @@ For checking the raw source code, use `seeInSource()`. * `param array|string` $selector optional +### dontSeeAuthentication + +Check that user is not authenticated. +You can specify whether users logged in with the 'remember me' option should be ignored by passing 'false' as a parameter. + +```php +dontSeeAuthentication(); +$I->dontSeeAuthentication(false); +``` + + * `param bool` $remembered + + ### dontSeeCheckboxIsChecked Check that the specified checkbox is unchecked. @@ -747,6 +776,15 @@ $I->haveHttpHeader('Client_Id', 'Codeception'); Invalidate previously cached routes. +### logout + +Invalidate the current session. +```php +logout(); +``` + + ### makeHtmlSnapshot Saves current page's HTML into a temprary file. @@ -866,6 +904,20 @@ For checking the raw source code, use `seeInSource()`. * `param array|string` $selector optional +### seeAuthentication + +Checks that a user is authenticated. +You can check users logged in with the option 'remember me' passing true as parameter. + +```php +seeAuthentication(); +$I->seeAuthentication(true); +``` + + * `param bool` $remembered + + ### seeCheckboxIsChecked Checks that the specified checkbox is checked. @@ -896,6 +948,19 @@ $I->seeCookie('PHPSESSID'); * `param array` $params +### seeCurrentActionIs + +Checks that current page matches action + +``` php +seeCurrentActionIs('PostController::index'); +$I->seeCurrentActionIs('HomeController'); +``` + + * `param string` $action + + ### seeCurrentRouteIs Checks that current url matches route. @@ -1092,6 +1157,21 @@ $I->seeInFormFields('//form[@id=my-form]', $form); * `param` $params +### seeInSession + +Assert that a session attribute exists. + +```php +seeInSession('attrib'); +$I->seeInSession('attrib', 'value'); +``` + + * `param string` $attrib + * `param mixed|null` $value + * `return` void + + ### seeInSource Checks that the current page contains the given string in its @@ -1228,6 +1308,18 @@ Checks that the response code is 5xx Checks that the response code 2xx +### seeUserHasRole + +Check that the current user has a role + +```php +seeUserHasRole('ROLE_ADMIN'); +``` + + * `param string` $role + + ### selectOption Selects an option in a select tag or in radio button group. diff --git a/src/Codeception/Module/Symfony.php b/src/Codeception/Module/Symfony.php index 1a0c6a9f..e54a36b4 100644 --- a/src/Codeception/Module/Symfony.php +++ b/src/Codeception/Module/Symfony.php @@ -13,6 +13,7 @@ use Symfony\Component\Finder\Finder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Finder\SplFileInfo; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Component\Console\Input\ArrayInput; @@ -787,15 +788,14 @@ private function getPossibleKernelClasses() */ public function seeNumRecords($expectedNum, $className, $criteria = []) { - $em = $this->_getEntityManager(); + $em = $this->_getEntityManager(); $repository = $em->getRepository($className); if (empty($criteria)) { - $currentNum = (int) $repository->createQueryBuilder('a') + $currentNum = (int)$repository->createQueryBuilder('a') ->select('count(a.id)') ->getQuery() - ->getSingleScalarResult() - ; + ->getSingleScalarResult(); } else { $currentNum = $repository->count($criteria); } @@ -809,4 +809,264 @@ public function seeNumRecords($expectedNum, $className, $criteria = []) ) ); } + + /** + * Invalidate the current session. + * ```php + * logout(); + * ``` + */ + public function logout() + { + $container = $this->_getContainer(); + + if ($container->has('security.token_storage')) { + $tokenStorage = $this->grabService('security.token_storage'); + $tokenStorage->setToken(null); + } + + if (!$container->has('session')) { + $this->fail("Symfony container doesn't have 'session' service"); + return; + } + $session = $this->grabService('session'); + + $sessionName = $session->getName(); + $session->invalidate(); + + $cookieJar = $this->client->getCookieJar(); + foreach ($cookieJar->all() as $cookie) { + $cookieName = $cookie->getName(); + if ($cookieName === 'MOCKSESSID' || + $cookieName === 'REMEMBERME' || + $cookieName === $sessionName + ) { + $cookieJar->expire($cookieName); + } + } + $cookieJar->flushExpiredCookies(); + } + + /** + * Assert that a session attribute exists. + * + * ```php + * seeInSession('attrib'); + * $I->seeInSession('attrib', 'value'); + * ``` + * + * @param string $attrib + * @param mixed|null $value + * @return void + */ + public function seeInSession($attrib, $value = null) + { + $container = $this->_getContainer(); + + if (!$container->has('session')) { + $this->fail("Symfony container doesn't have 'session' service"); + return; + } + + $session = $this->grabService('session'); + + if (!$session->has($attrib)) { + $this->fail("No session attribute with name '$attrib'"); + } + + if (null !== $value) { + $this->assertEquals($value, $session->get($attrib)); + } + } + + /** + * Opens web page by action name + * + * ``` php + * amOnAction('PostController::index'); + * $I->amOnAction('HomeController'); + * $I->amOnAction('ArticleController', ['slug' => 'lorem-ipsum']); + * ``` + * + * @param string $action + * @param array $params + */ + public function amOnAction($action, $params = []) + { + $container = $this->_getContainer(); + + if (!$container->has('router')) { + $this->fail("Symfony container doesn't have 'router' service"); + return; + } + + $router = $this->grabService('router'); + + $routes = $router->getRouteCollection()->getIterator(); + + foreach ($routes as $route) { + $controller = basename($route->getDefault('_controller')); + if ($controller === $action) { + $resource = $router->match($route->getPath()); + $url = $router->generate( + $resource['_route'], + $params, + UrlGeneratorInterface::ABSOLUTE_PATH + ); + $this->amOnPage($url); + return; + } + } + } + + /** + * Checks that a user is authenticated. + * You can check users logged in with the option 'remember me' passing true as parameter. + * + * ```php + * seeAuthentication(); + * $I->seeAuthentication(true); + * ``` + * + * @param bool $remembered + */ + public function seeAuthentication($remembered = false) + { + $container = $this->_getContainer(); + + if (!$container->has('security.helper')) { + $this->fail("Symfony container doesn't have 'security.helper' service"); + return; + } + + $security = $this->grabService('security.helper'); + + $user = $security->getUser(); + + if (!$user) { + $this->fail('There is no user in session'); + return; + } + + if ($remembered) { + $role = 'IS_AUTHENTICATED_REMEMBERED'; + } else { + $role = 'IS_AUTHENTICATED_FULLY'; + } + + $this->assertTrue($security->isGranted($role), 'There is no authenticated user'); + } + + /** + * Check that the current user has a role + * + * ```php + * seeUserHasRole('ROLE_ADMIN'); + * ``` + * + * @param string $role + */ + public function seeUserHasRole($role) + { + $container = $this->_getContainer(); + + if (!$container->has('security.helper')) { + $this->fail("Symfony container doesn't have 'security.helper' service"); + return; + } + + $security = $this->grabService('security.helper'); + + $user = $security->getUser(); + + if (!$user) { + $this->fail('There is no user in session'); + return; + } + + $this->assertTrue( + $security->isGranted($role), + sprintf( + "User %s has no role %s", + $user->getUsername(), + $role + ) + ); + } + + /** + * Check that user is not authenticated. + * You can specify whether users logged in with the 'remember me' option should be ignored by passing 'false' as a parameter. + * + * ```php + * dontSeeAuthentication(); + * ``` + * + * @param bool $remembered + */ + public function dontSeeAuthentication($remembered = true) + { + $container = $this->_getContainer(); + + if (!$container->has('security.helper')) { + $this->fail("Symfony container doesn't have 'security.helper' service"); + return; + } + + $security = $this->grabService('security.helper'); + + if ($remembered) { + $role = 'IS_AUTHENTICATED_REMEMBERED'; + } else { + $role = 'IS_AUTHENTICATED_FULLY'; + } + + $this->assertFalse( + $security->isGranted($role), + 'There is an user authenticated' + ); + } + + /** + * Checks that current page matches action + * + * ``` php + * seeCurrentActionIs('PostController::index'); + * $I->seeCurrentActionIs('HomeController'); + * ``` + * + * @param string $action + */ + public function seeCurrentActionIs($action) + { + $container = $this->_getContainer(); + + if (!$container->has('router')) { + $this->fail("Symfony container doesn't have 'router' service"); + return; + } + + $router = $this->grabService('router'); + + $routes = $router->getRouteCollection()->getIterator(); + + foreach ($routes as $route) { + $controller = basename($route->getDefault('_controller')); + if ($controller === $action) { + $request = $this->client->getRequest(); + $currentAction = basename($request->attributes->get('_controller')); + + $this->assertEquals($currentAction, $action, "Current action is '$currentAction'."); + return; + } + } + $this->fail("Action '$action' does not exist"); + } }