diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ab42b8c5..885dd616 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,12 +9,14 @@ jobs: strategy: matrix: php: [8.0, 8.1, 8.2] - symfony: ["4.4.*", "5.4.*", "6.0.*", "6.1.*", "6.2.*"] + symfony: ["4.4.*", "5.4.*", "6.0.*", "6.1.*", "6.2.*", "6.3.*"] exclude: - php: 8.0 symfony: "6.1.*" - php: 8.0 symfony: "6.2.*" + - php: 8.0 + symfony: "6.3.*" steps: - name: Checkout code @@ -68,6 +70,14 @@ jobs: path: framework-tests ref: "6.2" + - name: Checkout Symfony 6.3 Sample + if: "matrix.symfony == '6.3.*'" + uses: actions/checkout@v2 + with: + repository: Codeception/symfony-module-tests + path: framework-tests + ref: "6.3" + - name: Get composer cache directory id: composer-cache run: echo "::set-output name=dir::$(composer config cache-files-dir)" @@ -79,6 +89,10 @@ jobs: key: ${{ runner.os }}-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} restore-keys: ${{ runner.os }}-${{ matrix.php }}-composer- + - name: Install PHPUnit 9 for Symfony 4.4, 5.4 and 6.0 + if: "matrix.symfony == '4.4.*' || matrix.symfony == '5.4.*' || matrix.symfony == '6.0.*'" + run: composer require --dev --no-update "phpunit/phpunit=^9.0" + - name: Install dependencies run: | composer require symfony/finder=${{ matrix.symfony }} --no-update @@ -97,6 +111,11 @@ jobs: run: composer validate working-directory: framework-tests + - name: Install PHPUnit 10 in framework-tests for Symfony 6.1 and 6.2 + if: "matrix.symfony == '6.1.*' || matrix.symfony == '6.2.*' || matrix.symfony == '6.3.*'" + run: composer require --dev --no-update "phpunit/phpunit=^10.0" + working-directory: framework-tests + - name: Install Symfony Sample run: | composer remove codeception/codeception codeception/module-asserts codeception/module-doctrine2 codeception/lib-innerbrowser codeception/module-symfony --dev --no-update diff --git a/composer.json b/composer.json index 1e03edcd..24d5822d 100644 --- a/composer.json +++ b/composer.json @@ -20,20 +20,36 @@ "require": { "php": "^8.0", "ext-json": "*", - "codeception/codeception": "^5.0.0-RC3", + "codeception/codeception": "^5.0.8", "codeception/lib-innerbrowser": "^3.1.1 | ^4.0" }, "require-dev": { "codeception/module-asserts": "^3.0", "codeception/module-doctrine2": "^3.0", "doctrine/orm": "^2.10", + "symfony/browser-kit": "^4.4 | ^5.0 | ^6.0", + "symfony/cache": "^4.4 | ^5.0 | ^6.0", + "symfony/config": "^4.4 | ^5.0 | ^6.0", + "symfony/dependency-injection": "^4.4 | ^5.0 | ^6.0", + "symfony/dom-crawler": "^4.4 | ^5.0 | ^6.0", + "symfony/error-handler": "^4.4 | ^5.0 | ^6.0", + "symfony/filesystem": "^4.4 | ^5.0 | ^6.0", "symfony/form": "^4.4 | ^5.0 | ^6.0", "symfony/framework-bundle": "^4.4 | ^5.0 | ^6.0", + "symfony/http-foundation": "^4.4 | ^5.0 | ^6.0", "symfony/http-kernel": "^4.4 | ^5.0 | ^6.0", "symfony/mailer": "^4.4 | ^5.0 | ^6.0", + "symfony/mime": "^4.4 | ^5.0 | ^6.0", + "symfony/options-resolver": "^4.4 | ^5.0 | ^6.0", + "symfony/property-access": "^4.4 | ^5.0 | ^6.0", + "symfony/property-info": "^4.4 | ^5.0 | ^6.0", "symfony/routing": "^4.4 | ^5.0 | ^6.0", "symfony/security-bundle": "^4.4 | ^5.0 | ^6.0", + "symfony/security-core": "^4.4 | ^5.0 | ^6.0", + "symfony/security-csrf": "^4.4 | ^5.0 | ^6.0", + "symfony/security-http": "^4.4 | ^5.0 | ^6.0", "symfony/twig-bundle": "^4.4 | ^5.0 | ^6.0", + "symfony/var-exporter": "^4.4 | ^5.0 | ^6.0", "vlucas/phpdotenv": "^4.2 | ^5.4" }, "suggest": { diff --git a/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php b/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php index cabd34f2..67dc1ddb 100644 --- a/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/BrowserAssertionsTrait.php @@ -23,7 +23,6 @@ trait BrowserAssertionsTrait * // Perform other requests * * ``` - * */ public function rebootClientKernel(): void { diff --git a/src/Codeception/Module/Symfony/ConsoleAssertionsTrait.php b/src/Codeception/Module/Symfony/ConsoleAssertionsTrait.php index d54e2bfa..66edec9e 100644 --- a/src/Codeception/Module/Symfony/ConsoleAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/ConsoleAssertionsTrait.php @@ -40,8 +40,12 @@ public function runSymfonyConsoleCommand(string $command, array $parameters = [] $this->assertSame( $expectedExitCode, $exitCode, - 'Command did not exit with code ' . $expectedExitCode - . ' but with ' . $exitCode . ': ' . $output + sprintf( + 'Command did not exit with code %d but with %d: %s', + $expectedExitCode, + $exitCode, + $output + ) ); return $output; diff --git a/src/Codeception/Module/Symfony/DoctrineAssertionsTrait.php b/src/Codeception/Module/Symfony/DoctrineAssertionsTrait.php index 9aa4a054..6f9f0bc4 100644 --- a/src/Codeception/Module/Symfony/DoctrineAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/DoctrineAssertionsTrait.php @@ -6,7 +6,6 @@ use Doctrine\ORM\EntityRepository; use function class_exists; -use function get_class; use function interface_exists; use function is_object; use function is_string; @@ -66,6 +65,7 @@ public function grabRepository(object|string $mixed): ?EntityRepository $getRepo = function () use ($mixed, $entityRepoClass, $isNotARepo): ?EntityRepository { if (!$repo = $this->grabService($mixed)) return null; + /** @var EntityRepository $repo */ if (!$repo instanceof $entityRepoClass) { $isNotARepo(); return null; diff --git a/src/Codeception/Module/Symfony/EventsAssertionsTrait.php b/src/Codeception/Module/Symfony/EventsAssertionsTrait.php index f4b47b98..0ef1ee4c 100644 --- a/src/Codeception/Module/Symfony/EventsAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/EventsAssertionsTrait.php @@ -5,44 +5,48 @@ namespace Codeception\Module\Symfony; use Symfony\Component\HttpKernel\DataCollector\EventDataCollector; -use Symfony\Component\VarDumper\Cloner\Data; -use function get_class; use function is_array; use function is_object; -use function strpos; trait EventsAssertionsTrait { /** - * Verifies that there were no orphan events during the test. + * Verifies that there were no events during the test. + * Both regular and orphan events are checked. * - * An orphan event is an event that was triggered by manually executing the - * [`dispatch()`](https://symfony.com/doc/current/components/event_dispatcher.html#dispatch-the-event) method - * of the EventDispatcher but was not handled by any listener after it was dispatched. + * ```php + * dontSeeEvent(); + * $I->dontSeeEvent('App\MyEvent'); + * $I->dontSeeEvent(['App\MyEvent', 'App\MyOtherEvent']); + * ``` + * + * @param string|string[]|null $expected + */ + public function dontSeeEvent(array|string $expected = null): void + { + $actualEvents = array_merge(array_column($this->getCalledListeners(), 'event')); + $actual = [$this->getOrphanedEvents(), $actualEvents]; + $this->assertEventTriggered(false, $expected, $actual); + } + + /** + * Verifies that one or more event listeners were not called during the test. * * ```php * dontSeeOrphanEvent(); - * $I->dontSeeOrphanEvent('App\MyEvent'); - * $I->dontSeeOrphanEvent(new App\Events\MyEvent()); - * $I->dontSeeOrphanEvent(['App\MyEvent', 'App\MyOtherEvent']); + * $I->dontSeeEventListenerIsCalled('App\MyEventListener'); + * $I->dontSeeEventListenerIsCalled(['App\MyEventListener', 'App\MyOtherEventListener']); + * $I->dontSeeEventListenerIsCalled('App\MyEventListener', 'my.event); + * $I->dontSeeEventListenerIsCalled('App\MyEventListener', ['my.event', 'my.other.event']); * ``` * - * @param object|string|string[] $expected + * @param class-string|class-string[] $expected + * @param string|string[] $events */ - public function dontSeeOrphanEvent(array|object|string $expected = null): void + public function dontSeeEventListenerIsCalled(array|object|string $expected, array|string $events = []): void { - $eventCollector = $this->grabEventCollector(__FUNCTION__); - - /** @var Data $data */ - $data = $eventCollector->getOrphanedEvents(); - $expected = is_array($expected) ? $expected : [$expected]; - - if ($expected === null) { - $this->assertSame(0, $data->count()); - } else { - $this->assertEventNotTriggered($data, $expected); - } + $this->assertListenerCalled(false, $expected, $events); } /** @@ -56,20 +60,19 @@ public function dontSeeOrphanEvent(array|object|string $expected = null): void * ``` * * @param object|string|string[] $expected + * @deprecated Use `dontSeeEventListenerIsCalled` instead. */ public function dontSeeEventTriggered(array|object|string $expected): void { - $eventCollector = $this->grabEventCollector(__FUNCTION__); - - /** @var Data $data */ - $data = $eventCollector->getCalledListeners(); - $expected = is_array($expected) ? $expected : [$expected]; - - $this->assertEventNotTriggered($data, $expected); + trigger_error( + 'dontSeeEventTriggered is deprecated, please use dontSeeEventListenerIsCalled instead', + E_USER_DEPRECATED + ); + $this->dontSeeEventListenerIsCalled($expected); } /** - * Verifies that one or more orphan events were dispatched during the test. + * Verifies that there were no orphan events during the test. * * An orphan event is an event that was triggered by manually executing the * [`dispatch()`](https://symfony.com/doc/current/components/event_dispatcher.html#dispatch-the-event) method @@ -77,22 +80,58 @@ public function dontSeeEventTriggered(array|object|string $expected): void * * ```php * seeOrphanEvent('App\MyEvent'); - * $I->seeOrphanEvent(new App\Events\MyEvent()); - * $I->seeOrphanEvent(['App\MyEvent', 'App\MyOtherEvent']); + * $I->dontSeeOrphanEvent(); + * $I->dontSeeOrphanEvent('App\MyEvent'); + * $I->dontSeeOrphanEvent(['App\MyEvent', 'App\MyOtherEvent']); * ``` * - * @param object|string|string[] $expected + * @param string|string[] $expected */ - public function seeOrphanEvent(array|object|string $expected): void + public function dontSeeOrphanEvent(array|string $expected = null): void { - $eventCollector = $this->grabEventCollector(__FUNCTION__); + $actual = [$this->getOrphanedEvents()]; + $this->assertEventTriggered(false, $expected, $actual); + } - /** @var Data $data */ - $data = $eventCollector->getOrphanedEvents(); - $expected = is_array($expected) ? $expected : [$expected]; + /** + * Verifies that one or more events were dispatched during the test. + * Both regular and orphan events are checked. + * + * If you need to verify that expected event is not orphan, + * add `dontSeeOrphanEvent` call. + * + * ```php + * seeEvent('App\MyEvent'); + * $I->seeEvent(['App\MyEvent', 'App\MyOtherEvent']); + * ``` + * + * @param string|string[] $expected + */ + public function seeEvent(array|string $expected): void + { + $actualEvents = array_merge(array_column($this->getCalledListeners(), 'event')); + $actual = [$this->getOrphanedEvents(), $actualEvents]; + $this->assertEventTriggered(true, $expected, $actual); + } - $this->assertEventTriggered($data, $expected); + /** + * Verifies that one or more event listeners were called during the test. + * + * ```php + * seeEventListenerIsCalled('App\MyEventListener'); + * $I->seeEventListenerIsCalled(['App\MyEventListener', 'App\MyOtherEventListener']); + * $I->seeEventListenerIsCalled('App\MyEventListener', 'my.event); + * $I->seeEventListenerIsCalled('App\MyEventListener', ['my.event', 'my.other.event']); + * ``` + * + * @param class-string|class-string[] $expected + * @param string|string[] $events + */ + public function seeEventListenerIsCalled(array|object|string $expected, array|string $events = []): void + { + $this->assertListenerCalled(true, $expected, $events); } /** @@ -106,68 +145,123 @@ public function seeOrphanEvent(array|object|string $expected): void * ``` * * @param object|string|string[] $expected + * @deprecated Use `seeEventListenerIsCalled` instead. */ public function seeEventTriggered(array|object|string $expected): void { - $eventCollector = $this->grabEventCollector(__FUNCTION__); + trigger_error( + 'seeEventTriggered is deprecated, please use seeEventListenerIsCalled instead', + E_USER_DEPRECATED + ); + $this->seeEventListenerIsCalled($expected); + } - /** @var Data $data */ - $data = $eventCollector->getCalledListeners(); - $expected = is_array($expected) ? $expected : [$expected]; + /** + * Verifies that one or more orphan events were dispatched during the test. + * + * An orphan event is an event that was triggered by manually executing the + * [`dispatch()`](https://symfony.com/doc/current/components/event_dispatcher.html#dispatch-the-event) method + * of the EventDispatcher but was not handled by any listener after it was dispatched. + * + * ```php + * seeOrphanEvent('App\MyEvent'); + * $I->seeOrphanEvent(['App\MyEvent', 'App\MyOtherEvent']); + * ``` + * + * @param string|string[] $expected + */ + public function seeOrphanEvent(array|string $expected): void + { + $actual = [$this->getOrphanedEvents()]; + $this->assertEventTriggered(true, $expected, $actual); + } - $this->assertEventTriggered($data, $expected); + protected function getCalledListeners(): array + { + $eventCollector = $this->grabEventCollector(__FUNCTION__); + $calledListeners = $eventCollector->getCalledListeners($this->getDefaultDispatcher()); + return [...$calledListeners->getValue(true)]; } - protected function assertEventNotTriggered(Data $data, array $expected): void + protected function getOrphanedEvents(): array { - $actual = $data->getValue(true); + $eventCollector = $this->grabEventCollector(__FUNCTION__); + $orphanedEvents = $eventCollector->getOrphanedEvents($this->getDefaultDispatcher()); + return [...$orphanedEvents->getValue(true)]; + } + + protected function assertEventTriggered(bool $assertTrue, array|object|string|null $expected, array $actual): void + { + $actualEvents = array_merge(...$actual); - foreach ($expected as $expectedEvent) { + if ($assertTrue) $this->assertNotEmpty($actualEvents, 'No event was triggered'); + if ($expected === null) { + $this->assertEmpty($actualEvents); + return; + } + + $expected = is_object($expected) ? $expected::class : $expected; + foreach ((array)$expected as $expectedEvent) { $expectedEvent = is_object($expectedEvent) ? $expectedEvent::class : $expectedEvent; - $this->assertFalse( - $this->eventWasTriggered($actual, (string)$expectedEvent), - "The '{$expectedEvent}' event triggered" - ); + $eventTriggered = in_array($expectedEvent, $actualEvents); + + $message = $assertTrue + ? "The '{$expectedEvent}' event did not trigger" + : "The '{$expectedEvent}' event triggered"; + $this->assertSame($assertTrue, $eventTriggered, $message); } } - protected function assertEventTriggered(Data $data, array $expected): void + protected function assertListenerCalled(bool $assertTrue, array|object|string $expectedListeners, array|object|string $expectedEvents): void { - if ($data->count() === 0) { - $this->fail('No event was triggered'); + $expectedListeners = is_array($expectedListeners) ? $expectedListeners : [$expectedListeners]; + $expectedEvents = is_array($expectedEvents) ? $expectedEvents : [$expectedEvents]; + + if (empty($expectedEvents)) { + $expectedEvents = [null]; + } elseif (count($expectedListeners) > 1) { + $this->fail('You cannot check for events when using multiple listeners. Make multiple assertions instead.'); } - $actual = $data->getValue(true); + $actualEvents = $this->getCalledListeners(); + if ($assertTrue && empty($actualEvents)) { + $this->fail('No event listener was called'); + } - foreach ($expected as $expectedEvent) { - $expectedEvent = is_object($expectedEvent) ? $expectedEvent::class : $expectedEvent; - $this->assertTrue( - $this->eventWasTriggered($actual, (string)$expectedEvent), - "The '{$expectedEvent}' event did not trigger" - ); + foreach ($expectedListeners as $expectedListener) { + $expectedListener = is_object($expectedListener) ? $expectedListener::class : $expectedListener; + + foreach ($expectedEvents as $expectedEvent) { + $listenerCalled = $this->listenerWasCalled($expectedListener, $expectedEvent, $actualEvents); + $message = "The '{$expectedListener}' listener was called" + . ($expectedEvent ? " for the '{$expectedEvent}' event" : ''); + $this->assertSame($assertTrue, $listenerCalled, $message); + } } } - protected function eventWasTriggered(array $actual, string $expectedEvent): bool + private function listenerWasCalled(string $expectedListener, ?string $expectedEvent, array $actualEvents): bool { - $triggered = false; - - foreach ($actual as $actualEvent) { - if (is_array($actualEvent)) { // Called Listeners - if (str_starts_with($actualEvent['pretty'], $expectedEvent)) { - $triggered = true; - } - } else { // Orphan Events - if ($actualEvent === $expectedEvent) { - $triggered = true; - } + foreach ($actualEvents as $actualEvent) { + if ( + isset($actualEvent['pretty'], $actualEvent['event']) + && str_starts_with($actualEvent['pretty'], $expectedListener) + && ($expectedEvent === null || $actualEvent['event'] === $expectedEvent) + ) { + return true; } } - return $triggered; + return false; + } + + protected function getDefaultDispatcher(): string + { + return 'event_dispatcher'; } protected function grabEventCollector(string $function): EventDataCollector { return $this->grabCollector('events', $function); } -} \ No newline at end of file +} diff --git a/src/Codeception/Module/Symfony/FormAssertionsTrait.php b/src/Codeception/Module/Symfony/FormAssertionsTrait.php index 8261ea9f..31940e15 100644 --- a/src/Codeception/Module/Symfony/FormAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/FormAssertionsTrait.php @@ -51,7 +51,7 @@ public function seeFormErrorMessage(string $field, string $message = null): void $formCollector = $this->grabFormCollector(__FUNCTION__); if (!$forms = $formCollector->getData()->getValue(true)['forms']) { - $this->fail('There are no forms on the current page.'); + $this->fail('No forms found on the current page.'); } $fields = []; @@ -73,7 +73,7 @@ public function seeFormErrorMessage(string $field, string $message = null): void } if (!in_array($field, $fields)) { - $this->fail("the field '{$field}' does not exist in the form."); + $this->fail("The field '{$field}' does not exist in the form."); } if (!array_key_exists($field, $errors)) { diff --git a/src/Codeception/Module/Symfony/MailerAssertionsTrait.php b/src/Codeception/Module/Symfony/MailerAssertionsTrait.php index cb82484a..4e61cb2d 100644 --- a/src/Codeception/Module/Symfony/MailerAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/MailerAssertionsTrait.php @@ -56,13 +56,11 @@ public function seeEmailIsSent(int $expectedCount = 1): void */ public function grabLastSentEmail(): ?Email { + /** @var Email[] $emails */ $emails = $this->getMessageMailerEvents()->getMessages(); - /** @var Email|false $lastEmail */ - if ($lastEmail = end($emails)) { - return $lastEmail; - } + $lastEmail = end($emails); - return null; + return $lastEmail ?: null; } /** diff --git a/src/Codeception/Module/Symfony/ParameterAssertionsTrait.php b/src/Codeception/Module/Symfony/ParameterAssertionsTrait.php index cb5bcad2..63231dd5 100644 --- a/src/Codeception/Module/Symfony/ParameterAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/ParameterAssertionsTrait.php @@ -16,13 +16,13 @@ trait ParameterAssertionsTrait * $I->grabParameter('app.business_name'); * ``` * - * @param string $name + * @param string $parameterName * @return array|bool|float|int|string|null */ - public function grabParameter(string $name) + public function grabParameter(string $parameterName) { $parameterBag = $this->grabParameterBagService(); - return $parameterBag->get($name); + return $parameterBag->get($parameterName); } protected function grabParameterBagService(): ParameterBagInterface diff --git a/src/Codeception/Module/Symfony/RouterAssertionsTrait.php b/src/Codeception/Module/Symfony/RouterAssertionsTrait.php index c023782f..e0bdeab0 100644 --- a/src/Codeception/Module/Symfony/RouterAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/RouterAssertionsTrait.php @@ -11,8 +11,6 @@ use function array_merge; use function explode; use function sprintf; -use function strlen; -use function substr_compare; trait RouterAssertionsTrait { @@ -32,7 +30,6 @@ trait RouterAssertionsTrait public function amOnAction(string $action, array $params = []): void { $router = $this->grabRouterService(); - $routes = $router->getRouteCollection()->getIterator(); foreach ($routes as $route) { @@ -66,7 +63,7 @@ public function amOnRoute(string $routeName, array $params = []): void { $router = $this->grabRouterService(); if ($router->getRouteCollection()->get($routeName) === null) { - $this->fail(sprintf('Route with name "%s" does not exists.', $routeName)); + $this->fail(sprintf('Route with name "%s" does not exist.', $routeName)); } $url = $router->generate($routeName, $params); @@ -95,7 +92,6 @@ public function invalidateCachedRouter(): void public function seeCurrentActionIs(string $action): void { $router = $this->grabRouterService(); - $routes = $router->getRouteCollection()->getIterator(); foreach ($routes as $route) { @@ -128,7 +124,7 @@ public function seeCurrentRouteIs(string $routeName, array $params = []): void { $router = $this->grabRouterService(); if ($router->getRouteCollection()->get($routeName) === null) { - $this->fail(sprintf('Route with name "%s" does not exists.', $routeName)); + $this->fail(sprintf('Route with name "%s" does not exist.', $routeName)); } $uri = explode('?', $this->grabFromCurrentUrl())[0]; @@ -160,7 +156,7 @@ public function seeInCurrentRoute(string $routeName): void { $router = $this->grabRouterService(); if ($router->getRouteCollection()->get($routeName) === null) { - $this->fail(sprintf('Route with name "%s" does not exists.', $routeName)); + $this->fail(sprintf('Route with name "%s" does not exist.', $routeName)); } $uri = explode('?', $this->grabFromCurrentUrl())[0]; diff --git a/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php b/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php index b53a72b8..bd9140c0 100644 --- a/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/ServicesAssertionsTrait.php @@ -20,7 +20,6 @@ trait ServicesAssertionsTrait * ``` * * @part services - * @param string $serviceId */ public function grabService(string $serviceId): object { @@ -69,15 +68,10 @@ public function persistPermanentService(string $serviceName): void */ public function unpersistService(string $serviceName): void { - if (isset($this->persistentServices[$serviceName])) { - unset($this->persistentServices[$serviceName]); - } - - if (isset($this->permanentServices[$serviceName])) { - unset($this->permanentServices[$serviceName]); - } + unset($this->persistentServices[$serviceName]); + unset($this->permanentServices[$serviceName]); - if ($this->client instanceof SymfonyConnector && isset($this->client->persistentServices[$serviceName])) { + if ($this->client instanceof SymfonyConnector) { unset($this->client->persistentServices[$serviceName]); } } diff --git a/src/Codeception/Module/Symfony/SessionAssertionsTrait.php b/src/Codeception/Module/Symfony/SessionAssertionsTrait.php index f6911303..a8b69afd 100644 --- a/src/Codeception/Module/Symfony/SessionAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/SessionAssertionsTrait.php @@ -29,37 +29,17 @@ trait SessionAssertionsTrait * ]); * $I->amLoggedInAs($user); * ``` - * - * @param UserInterface $user - * @param string $firewallName - * @param null $firewallContext */ - public function amLoggedInAs(UserInterface $user, string $firewallName = 'main', $firewallContext = null): void + public function amLoggedInAs(UserInterface $user, string $firewallName = 'main', string $firewallContext = null): void { $session = $this->getCurrentSession(); + $roles = $user->getRoles(); - if ($this->getSymfonyMajorVersion() < 6) { - if ($this->config['guard']) { - $token = new PostAuthenticationGuardToken($user, $firewallName, $user->getRoles()); - } else { - $token = new UsernamePasswordToken($user, null, $firewallName, $user->getRoles()); - } - } else { - if ($this->config['authenticator']) { - $token = new PostAuthenticationToken($user, $firewallName, $user->getRoles()); - } else { - $token = new UsernamePasswordToken($user, $firewallName, $user->getRoles()); - } - } - + $token = $this->createAuthenticationToken($user, $firewallName, $roles); $this->getTokenStorage()->setToken($token); - if ($firewallContext) { - $session->set('_security_' . $firewallContext, serialize($token)); - } else { - $session->set('_security_' . $firewallName, serialize($token)); - } - + $sessionKey = $firewallContext ? "_security_{$firewallContext}" : "_security_{$firewallName}"; + $session->set($sessionKey, serialize($token)); $session->save(); $cookie = new Cookie($session->getName(), $session->getId()); @@ -74,16 +54,13 @@ public function amLoggedInAs(UserInterface $user, string $firewallName = 'main', * $I->dontSeeInSession('attribute'); * $I->dontSeeInSession('attribute', 'value'); * ``` - * */ public function dontSeeInSession(string $attribute, mixed $value = null): void { $session = $this->getCurrentSession(); - if ($attributeExists = $session->has($attribute)) { - $this->fail("Session attribute with name '{$attribute}' does exist"); - } - $this->assertFalse($attributeExists); + $attributeExists = $session->has($attribute); + $this->assertFalse($attributeExists, "Session attribute '{$attribute}' exists."); if (null !== $value) { $this->assertNotSame($value, $session->get($attribute)); @@ -98,8 +75,7 @@ public function dontSeeInSession(string $attribute, mixed $value = null): void */ public function goToLogoutPath(): void { - $logoutUrlGenerator = $this->getLogoutUrlGenerator(); - $logoutPath = $logoutUrlGenerator->getLogoutPath(); + $logoutPath = $this->getLogoutUrlGenerator()->getLogoutPath(); $this->amOnPage($logoutPath); } @@ -132,17 +108,14 @@ public function logoutProgrammatically(): void } $session = $this->getCurrentSession(); - $sessionName = $session->getName(); $session->invalidate(); $cookieJar = $this->client->getCookieJar(); + $cookiesToExpire = ['MOCKSESSID', 'REMEMBERME', $sessionName]; foreach ($cookieJar->all() as $cookie) { $cookieName = $cookie->getName(); - if ($cookieName === 'MOCKSESSID' || - $cookieName === 'REMEMBERME' || - $cookieName === $sessionName - ) { + if (in_array($cookieName, $cookiesToExpire, true)) { $cookieJar->expire($cookieName); } } @@ -163,10 +136,8 @@ public function seeInSession(string $attribute, mixed $value = null): void { $session = $this->getCurrentSession(); - if (!$attributeExists = $session->has($attribute)) { - $this->fail("No session attribute with name '{$attribute}'"); - } - $this->assertTrue($attributeExists); + $attributeExists = $session->has($attribute); + $this->assertTrue($attributeExists, "No session attribute with name '{$attribute}'"); if (null !== $value) { $this->assertSame($value, $session->get($attribute)); @@ -181,8 +152,6 @@ public function seeInSession(string $attribute, mixed $value = null): void * $I->seeSessionHasValues(['key1', 'key2']); * $I->seeSessionHasValues(['key1' => 'value1', 'key2' => 'value2']); * ``` - * - * @param array $bindings */ public function seeSessionHasValues(array $bindings): void { @@ -227,4 +196,20 @@ protected function getSymfonyMajorVersion(): int { return $this->kernel::MAJOR_VERSION; } + + /** + * @return UsernamePasswordToken|PostAuthenticationGuardToken|PostAuthenticationToken + */ + protected function createAuthenticationToken(UserInterface $user, string $firewallName, array $roles) + { + if ($this->getSymfonyMajorVersion() < 6) { + return $this->config['guard'] + ? new PostAuthenticationGuardToken($user, $firewallName, $roles) + : new UsernamePasswordToken($user, null, $firewallName, $roles); + } + + return $this->config['authenticator'] + ? new PostAuthenticationToken($user, $firewallName, $roles) + : new UsernamePasswordToken($user, $firewallName, $roles); + } } diff --git a/src/Codeception/Module/Symfony/TimeAssertionsTrait.php b/src/Codeception/Module/Symfony/TimeAssertionsTrait.php index d48222eb..136bef25 100644 --- a/src/Codeception/Module/Symfony/TimeAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/TimeAssertionsTrait.php @@ -36,7 +36,7 @@ public function seeRequestTimeIsLessThan(int|float $expectedMilliseconds): void $expectedMilliseconds, $actualMilliseconds, sprintf( - 'The request was expected to last less than %d ms, but it actually lasted %d ms.', + 'The request duration was expected to be less than %d ms, but it was actually %d ms.', $expectedMilliseconds, $actualMilliseconds ) diff --git a/src/Codeception/Module/Symfony/TwigAssertionsTrait.php b/src/Codeception/Module/Symfony/TwigAssertionsTrait.php index 624b822e..52b02d0d 100644 --- a/src/Codeception/Module/Symfony/TwigAssertionsTrait.php +++ b/src/Codeception/Module/Symfony/TwigAssertionsTrait.php @@ -16,8 +16,6 @@ trait TwigAssertionsTrait * dontSeeRenderedTemplate('home.html.twig'); * ``` - * - * @param string $template */ public function dontSeeRenderedTemplate(string $template): void { @@ -39,15 +37,13 @@ public function dontSeeRenderedTemplate(string $template): void * seeCurrentTemplateIs('home.html.twig'); * ``` - * - * @param string $expectedTemplate */ public function seeCurrentTemplateIs(string $expectedTemplate): void { $twigCollector = $this->grabTwigCollector(__FUNCTION__); $templates = (array)$twigCollector->getTemplates(); - $actualTemplate = (string)array_key_first($templates); + $actualTemplate = !empty($templates) ? (string) array_key_first($templates) : 'N/A'; $this->assertSame( $expectedTemplate, @@ -65,8 +61,6 @@ public function seeCurrentTemplateIs(string $expectedTemplate): void * $I->seeRenderedTemplate('home.html.twig'); * $I->seeRenderedTemplate('layout.html.twig'); * ``` - * - * @param string $template */ public function seeRenderedTemplate(string $template): void {