From 04ce515b3dbd7a50a505c96723e061845d869282 Mon Sep 17 00:00:00 2001 From: Baptiste Lafontaine Date: Thu, 27 Jan 2022 16:39:15 +0100 Subject: [PATCH 01/15] [WIP] Sf 6 compatibility --- composer.json | 22 +++++++++++----------- src/QueryCountClientTrait.php | 4 +++- tests/App/AppKernel.php | 8 ++++---- tests/App/Entity/User.php | 7 ++++++- tests/App/config.yml | 5 ++--- tests/Test/WebTestCaseTest.php | 2 +- 6 files changed, 27 insertions(+), 21 deletions(-) diff --git a/composer.json b/composer.json index 969f094b..fcbfafdf 100644 --- a/composer.json +++ b/composer.json @@ -18,24 +18,24 @@ "php": "^7.2 || ^8.0", "doctrine/annotations": "^1.3", "phpunit/phpunit": "^7.5.0 || ^8.0 || ^9.0", - "symfony/browser-kit": "^4.4 || ^5.1", - "symfony/framework-bundle": "^4.4 || ^5.1" + "symfony/browser-kit": "^4.4 || ^5.1 || ^6.0", + "symfony/framework-bundle": "^4.4 || ^5.1 || ^6.0" }, "require-dev": { "ext-json": "*", "doctrine/doctrine-bundle": "^2.1", "doctrine/orm": "^2.7", "monolog/monolog": "~1.11", - "symfony/css-selector": "^4.4 || ^5.1", - "symfony/doctrine-bridge": "^4.4 || ^5.1", - "symfony/form": "^4.4 || ^5.1", - "symfony/http-kernel": "^4.4 || ^5.1", + "symfony/css-selector": "^4.4 || ^5.1 || ^6.0", + "symfony/doctrine-bridge": "^4.4 || ^5.1 || ^6.0", + "symfony/form": "^4.4 || ^5.1 || ^6.0", + "symfony/http-kernel": "^4.4 || ^5.1 || ^6.0", "symfony/monolog-bundle": "^3.4", - "symfony/phpunit-bridge": "^4.4 || ^5.1", - "symfony/security-bundle": "^4.4 || ^5.1", - "symfony/twig-bundle": "^4.4 || ^5.1", - "symfony/validator": "^4.4 || ^5.1", - "symfony/yaml": "^4.4 || ^5.1", + "symfony/phpunit-bridge": "^4.4 || ^5.1 || ^6.0", + "symfony/security-bundle": "^4.4 || ^5.1 || ^6.0", + "symfony/twig-bundle": "^4.4 || ^5.1 || ^6.0", + "symfony/validator": "^4.4 || ^5.1 || ^6.0", + "symfony/yaml": "^4.4 || ^5.1 || ^6.0", "twig/twig": "^2.0 || ^3.0" }, "conflict": { diff --git a/src/QueryCountClientTrait.php b/src/QueryCountClientTrait.php index d710f104..31d8b061 100644 --- a/src/QueryCountClientTrait.php +++ b/src/QueryCountClientTrait.php @@ -13,6 +13,8 @@ namespace Liip\FunctionalTestBundle; +use Symfony\Component\DomCrawler\Crawler; + /** * @author Sullivan Senechal * @@ -28,7 +30,7 @@ public function request( array $server = [], string $content = null, bool $changeHistory = true - ) { + ): Crawler { $crawler = parent::request($method, $uri, $parameters, $files, $server, $content, $changeHistory); $this->checkQueryCount(); diff --git a/tests/App/AppKernel.php b/tests/App/AppKernel.php index c98e5284..d594e269 100644 --- a/tests/App/AppKernel.php +++ b/tests/App/AppKernel.php @@ -38,22 +38,22 @@ public function registerContainerConfiguration(LoaderInterface $loader): void $loader->load(__DIR__.'/config.yml'); } - public function getCacheDir() + public function getCacheDir(): string { return $this->getBaseDir().'cache'; } - public function getLogDir() + public function getLogDir(): string { return $this->getBaseDir().'log'; } - protected function getBaseDir() + protected function getBaseDir(): string { return sys_get_temp_dir().'/LiipFunctionalTestBundle/'.(new \ReflectionClass($this))->getShortName().'/var/'; } - public function getProjectDir() + public function getProjectDir(): string { return __DIR__; } diff --git a/tests/App/Entity/User.php b/tests/App/Entity/User.php index 944766a3..e3fd4bf3 100644 --- a/tests/App/Entity/User.php +++ b/tests/App/Entity/User.php @@ -279,7 +279,7 @@ public function getConfirmationToken() // Functions required for compatibility with UserInterface // @see http://symfony.com/doc/2.3/cookbook/security/custom_provider.html - public function getRoles() + public function getRoles(): array { return ['ROLE_ADMIN']; } @@ -289,6 +289,11 @@ public function getUsername() return $this->getName(); } + public function getUserIdentifier(): string + { + return $this->getName(); + } + public function eraseCredentials(): void { } diff --git a/tests/App/config.yml b/tests/App/config.yml index 6617ed82..60679cb7 100644 --- a/tests/App/config.yml +++ b/tests/App/config.yml @@ -11,7 +11,7 @@ framework: session: # handler_id set to null will use default session handler from php.ini handler_id: ~ - storage_id: session.storage.mock_file + storage_factory_id: session.storage.factory.mock_file # https://groups.google.com/forum/#!topic/symfony2/IB-CpMgo5o0 name: MOCKSESSID profiler: @@ -47,7 +47,7 @@ doctrine: prefix: 'Liip\Acme\Tests\App\Entity' security: - encoders: + password_hashers: # in_memory users Symfony\Component\Security\Core\User\User: plaintext # User entity @@ -67,7 +67,6 @@ security: firewalls: secured_area: pattern: ^/admin - anonymous: lazy http_basic: realm: "Admin Area" provider: chain_provider diff --git a/tests/Test/WebTestCaseTest.php b/tests/Test/WebTestCaseTest.php index 7fb4244f..e9caf16e 100644 --- a/tests/Test/WebTestCaseTest.php +++ b/tests/Test/WebTestCaseTest.php @@ -29,7 +29,7 @@ protected function setUp(): void static::$class = AppKernel::class; } - public static function getKernelClass() + public static function getKernelClass(): string { return AppKernel::class; } From 2433d273f6344e05cc461ac4ba55f837067e6faa Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Sat, 14 May 2022 00:04:11 +0200 Subject: [PATCH 02/15] CI: add test with Symfony 6 --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 855b8732..46afcc8f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -25,6 +25,8 @@ jobs: symfony-version: "^4.4" - php-version: 8.0 symfony-version: "^4.4" + - php-version: 8.1 + symfony-version: "^6.0" steps: - name: Checkout From d27d4e7991ba08e4900d7a1f8e1ce3ca9b51edbc Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Sat, 14 May 2022 02:04:40 +0200 Subject: [PATCH 03/15] Load different config files for framework.session --- tests/App/AppKernel.php | 8 ++++++++ tests/App/config.yml | 11 ----------- tests/App/security_4.yml | 6 ++++++ tests/App/security_5.yml | 7 +++++++ tests/App/session_4.yml | 7 +++++++ tests/App/session_5.yml | 7 +++++++ 6 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 tests/App/security_4.yml create mode 100644 tests/App/security_5.yml create mode 100644 tests/App/session_4.yml create mode 100644 tests/App/session_5.yml diff --git a/tests/App/AppKernel.php b/tests/App/AppKernel.php index d594e269..64128a60 100644 --- a/tests/App/AppKernel.php +++ b/tests/App/AppKernel.php @@ -36,6 +36,14 @@ public function registerBundles(): array public function registerContainerConfiguration(LoaderInterface $loader): void { $loader->load(__DIR__.'/config.yml'); + + if (Kernel::MAJOR_VERSION >= 5) { + $loader->load(__DIR__.'/security_5.yml'); + $loader->load(__DIR__.'/session_5.yml'); + } else { + $loader->load(__DIR__.'/security_4.yml'); + $loader->load(__DIR__.'/session_4.yml'); + } } public function getCacheDir(): string diff --git a/tests/App/config.yml b/tests/App/config.yml index 60679cb7..f05e7009 100644 --- a/tests/App/config.yml +++ b/tests/App/config.yml @@ -8,12 +8,6 @@ framework: form: true csrf_protection: true property_access: ~ - session: - # handler_id set to null will use default session handler from php.ini - handler_id: ~ - storage_factory_id: session.storage.factory.mock_file - # https://groups.google.com/forum/#!topic/symfony2/IB-CpMgo5o0 - name: MOCKSESSID profiler: collect: false @@ -47,11 +41,6 @@ doctrine: prefix: 'Liip\Acme\Tests\App\Entity' security: - password_hashers: - # in_memory users - Symfony\Component\Security\Core\User\User: plaintext - # User entity - Liip\Acme\Tests\App\Entity\User: plaintext providers: chain_provider: chain: diff --git a/tests/App/security_4.yml b/tests/App/security_4.yml new file mode 100644 index 00000000..142c7ed3 --- /dev/null +++ b/tests/App/security_4.yml @@ -0,0 +1,6 @@ +security: + encoders: + # in_memory users + Symfony\Component\Security\Core\User\User: plaintext + # User entity + Liip\Acme\Tests\App\Entity\User: plaintext diff --git a/tests/App/security_5.yml b/tests/App/security_5.yml new file mode 100644 index 00000000..c7a4c763 --- /dev/null +++ b/tests/App/security_5.yml @@ -0,0 +1,7 @@ +security: + password_hashers: + # in_memory users + Symfony\Component\Security\Core\User\User: plaintext + Symfony\Component\Security\Core\User\InMemoryUser: plaintext + # User entity + Liip\Acme\Tests\App\Entity\User: plaintext diff --git a/tests/App/session_4.yml b/tests/App/session_4.yml new file mode 100644 index 00000000..929a36d1 --- /dev/null +++ b/tests/App/session_4.yml @@ -0,0 +1,7 @@ +framework: + session: + # handler_id set to null will use default session handler from php.ini + handler_id: ~ + storage_id: session.storage.mock_file + # https://groups.google.com/forum/#!topic/symfony2/IB-CpMgo5o0 + name: MOCKSESSID diff --git a/tests/App/session_5.yml b/tests/App/session_5.yml new file mode 100644 index 00000000..e0cbd8ef --- /dev/null +++ b/tests/App/session_5.yml @@ -0,0 +1,7 @@ +framework: + session: + # handler_id set to null will use default session handler from php.ini + handler_id: ~ + storage_factory_id: session.storage.factory.mock_file + # https://groups.google.com/forum/#!topic/symfony2/IB-CpMgo5o0 + name: MOCKSESSID From 496bfd3143c4a70be3d8192b052aa495669bcbf5 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Sat, 14 May 2022 02:27:42 +0200 Subject: [PATCH 04/15] Call the session service through class name instead of alias --- src/Test/WebTestCase.php | 21 +++++++++++++++++++-- tests/App/Controller/DefaultController.php | 11 ++++++----- tests/App/Resources/views/layout.html.twig | 4 ++-- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/Test/WebTestCase.php b/src/Test/WebTestCase.php index 084cb90e..26884f26 100644 --- a/src/Test/WebTestCase.php +++ b/src/Test/WebTestCase.php @@ -25,6 +25,7 @@ use Symfony\Component\DependencyInjection\ResettableContainerInterface; use Symfony\Component\DomCrawler\Crawler; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -433,7 +434,7 @@ public function loginClient(KernelBrowser $client, UserInterface $user, string $ throw new \InvalidArgumentException('Missing session.storage.options#name'); } - $session = $client->getContainer()->get('session'); + $session = $this->getSession($client); $session->setId(uniqid()); $client->getCookieJar()->set(new Cookie($options['name'], $session->getId())); @@ -507,7 +508,7 @@ protected function createClientWithParams(array $params, ?string $username = nul throw new \InvalidArgumentException('Missing session.storage.options#name'); } - $session = $client->getContainer()->get('session'); + $session = $this->getSession($client); $session->setId(uniqid()); $client->getCookieJar()->set(new Cookie($options['name'], $session->getId())); @@ -527,4 +528,20 @@ protected function createClientWithParams(array $params, ?string $username = nul return $client; } + + /** + * Compatibility layer. + */ + private function getSession($client) + { + $container = $client->getContainer(); + + if ($container->has(SessionInterface::class)) { + return $container->get(SessionInterface::class); + } elseif ($container->has('session')) { + return $container->get('session'); + } + + throw new \Exception('Session is not available.'); + } } diff --git a/tests/App/Controller/DefaultController.php b/tests/App/Controller/DefaultController.php index c02aa159..2c22019f 100644 --- a/tests/App/Controller/DefaultController.php +++ b/tests/App/Controller/DefaultController.php @@ -74,16 +74,17 @@ private function form(Request $request, string $template): Response $form->handleRequest($request); + $flashMessage = null; if ($form->isSubmitted() && $form->isValid()) { - $this->get('session')->getFlashBag()->add( - 'notice', - 'Name submitted.' - ); + $flashMessage = 'Name submitted.'; } return $this->render( $template, - ['form' => $form->createView()] + [ + 'form' => $form->createView(), + 'flash_message' => $flashMessage, + ] ); } diff --git a/tests/App/Resources/views/layout.html.twig b/tests/App/Resources/views/layout.html.twig index ab53f32a..ec3a74af 100644 --- a/tests/App/Resources/views/layout.html.twig +++ b/tests/App/Resources/views/layout.html.twig @@ -18,11 +18,11 @@

LiipFunctionalTestBundle

- {% for flash_message in app.session.flashbag.get('notice') %} + {% if flash_message|default(false) %}
{{ flash_message }}
- {% endfor %} + {% endif %}
{% block body %}{% endblock %}
From 293438871c3d3cbd43ee6930017aee5e3bd601be Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Sat, 14 May 2022 02:48:04 +0200 Subject: [PATCH 05/15] Remove call to getDoctrine(), inject entity manager instead --- tests/App/Controller/DefaultController.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/App/Controller/DefaultController.php b/tests/App/Controller/DefaultController.php index 2c22019f..ed4364c9 100644 --- a/tests/App/Controller/DefaultController.php +++ b/tests/App/Controller/DefaultController.php @@ -13,6 +13,7 @@ namespace Liip\Acme\Tests\App\Controller; +use Doctrine\ORM\EntityManagerInterface; use Liip\Acme\Tests\App\Entity\User; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -30,10 +31,10 @@ public function indexAction(): Response ); } - public function userAction(int $userId): Response + public function userAction(EntityManagerInterface $entityManager, int $userId): Response { /** @var \Liip\Acme\Tests\App\Entity\User $user */ - $user = $this->getDoctrine() + $user = $entityManager ->getRepository(User::class) ->find($userId); From a6ab36b026c4796fbe1d3fd7dbf10d489cc6ad9e Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Sat, 14 May 2022 02:54:12 +0200 Subject: [PATCH 06/15] User: add the __toString() method --- tests/App/Entity/User.php | 5 +++++ tests/App/Resources/views/layout.html.twig | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/App/Entity/User.php b/tests/App/Entity/User.php index e3fd4bf3..9b67826f 100644 --- a/tests/App/Entity/User.php +++ b/tests/App/Entity/User.php @@ -84,6 +84,11 @@ public function __construct() ); } + public function __toString(): string + { + return $this->getUserIdentifier(); + } + /** * Set id. * diff --git a/tests/App/Resources/views/layout.html.twig b/tests/App/Resources/views/layout.html.twig index ec3a74af..a31f36e3 100644 --- a/tests/App/Resources/views/layout.html.twig +++ b/tests/App/Resources/views/layout.html.twig @@ -12,7 +12,7 @@ {%- if not is_granted('IS_AUTHENTICATED_REMEMBERED') -%} Not logged in. {%- else -%} - Logged in as {{ app.user.username }}. + Logged in as {{ app.user }}. {%- endif -%}

From 1de5de1b5e94046a42d6498f92eeb7e8fe434807 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Sat, 14 May 2022 02:56:53 +0200 Subject: [PATCH 07/15] Add access to session for Symfony 6 --- src/Test/WebTestCase.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Test/WebTestCase.php b/src/Test/WebTestCase.php index 26884f26..9d9374c2 100644 --- a/src/Test/WebTestCase.php +++ b/src/Test/WebTestCase.php @@ -24,6 +24,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ResettableContainerInterface; use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\KernelInterface; @@ -532,13 +533,20 @@ protected function createClientWithParams(array $params, ?string $username = nul /** * Compatibility layer. */ - private function getSession($client) + private function getSession(KernelBrowser $client): SessionInterface { $container = $client->getContainer(); + // Available before Symfony 6 if ($container->has(SessionInterface::class)) { return $container->get(SessionInterface::class); - } elseif ($container->has('session')) { + } + // Preferred since Symfony 5.4 + elseif ($container->has(RequestStack::class)) { + return $container->get(RequestStack::class)->getSession(); + } + // For Symfony 4.4 + elseif ($container->has('session')) { return $container->get('session'); } From efd66ab32ccf8058845531af1bd82ff7fbba4deb Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Wed, 18 May 2022 13:29:38 +0200 Subject: [PATCH 08/15] Call loginUser() when it's available, it's provided by Symfony --- src/Test/WebTestCase.php | 25 ++++++++++++++++++++----- tests/Test/WebTestCaseConfigTest.php | 2 ++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Test/WebTestCase.php b/src/Test/WebTestCase.php index 9d9374c2..e9f36b1d 100644 --- a/src/Test/WebTestCase.php +++ b/src/Test/WebTestCase.php @@ -24,7 +24,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ResettableContainerInterface; use Symfony\Component\DomCrawler\Crawler; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\KernelInterface; @@ -428,6 +427,16 @@ public function loginAs(UserInterface $user, string $firewallName): self public function loginClient(KernelBrowser $client, UserInterface $user, string $firewallName): void { + // Available since Symfony 5.1 + if (method_exists($client, 'loginUser')) { + // TODO: on next minor release: + // trigger deprecation if Symfony ≥ 5.1 → https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication + + $client->loginUser($user); + + return; + } + // has to be set otherwise "hasPreviousSession" in Request returns false. $options = $client->getContainer()->getParameter('session.storage.options'); @@ -518,6 +527,16 @@ protected function createClientWithParams(array $params, ?string $username = nul foreach ($this->firewallLogins as $firewallName => $user) { $token = $this->createUserToken($user, $firewallName); + // Available since Symfony 5.1 + if (method_exists($client, 'loginUser')) { + // TODO: on next minor release: + // trigger deprecation if Symfony ≥ 5.1 → https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication + + $client->loginUser($user); + + continue; + } + $tokenStorage = $client->getContainer()->get('security.token_storage'); $tokenStorage->setToken($token); @@ -541,10 +560,6 @@ private function getSession(KernelBrowser $client): SessionInterface if ($container->has(SessionInterface::class)) { return $container->get(SessionInterface::class); } - // Preferred since Symfony 5.4 - elseif ($container->has(RequestStack::class)) { - return $container->get(RequestStack::class)->getSession(); - } // For Symfony 4.4 elseif ($container->has('session')) { return $container->get('session'); diff --git a/tests/Test/WebTestCaseConfigTest.php b/tests/Test/WebTestCaseConfigTest.php index c236ea18..ed3d8d44 100644 --- a/tests/Test/WebTestCaseConfigTest.php +++ b/tests/Test/WebTestCaseConfigTest.php @@ -109,6 +109,8 @@ public function testIndexAuthenticatedClient(): void /** * Log in as the user defined in the Data Fixture. + * + * loginAs() is deprecated but we test if for Backward Compatibility. */ public function testIndexAuthenticationLoginAs(): void { From e23601e2eb07082d7a5ad91d6a97d4fde3f8fc55 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Wed, 18 May 2022 13:39:43 +0200 Subject: [PATCH 09/15] Start the session in createClientWithParams() --- src/Test/WebTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Test/WebTestCase.php b/src/Test/WebTestCase.php index e9f36b1d..8e26ea1c 100644 --- a/src/Test/WebTestCase.php +++ b/src/Test/WebTestCase.php @@ -519,7 +519,7 @@ protected function createClientWithParams(array $params, ?string $username = nul } $session = $this->getSession($client); - $session->setId(uniqid()); + $session->start(); $client->getCookieJar()->set(new Cookie($options['name'], $session->getId())); From f335198361d7bac3906fd630bc934828b6adbf76 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Thu, 19 May 2022 02:03:51 +0200 Subject: [PATCH 10/15] With Symfony 6.0, start a session if no one is available --- src/Test/WebTestCase.php | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/Test/WebTestCase.php b/src/Test/WebTestCase.php index 8e26ea1c..bcc0384e 100644 --- a/src/Test/WebTestCase.php +++ b/src/Test/WebTestCase.php @@ -24,7 +24,11 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ResettableContainerInterface; use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -445,7 +449,6 @@ public function loginClient(KernelBrowser $client, UserInterface $user, string $ } $session = $this->getSession($client); - $session->setId(uniqid()); $client->getCookieJar()->set(new Cookie($options['name'], $session->getId())); @@ -519,7 +522,6 @@ protected function createClientWithParams(array $params, ?string $username = nul } $session = $this->getSession($client); - $session->start(); $client->getCookieJar()->set(new Cookie($options['name'], $session->getId())); @@ -556,15 +558,35 @@ private function getSession(KernelBrowser $client): SessionInterface { $container = $client->getContainer(); + // Preferred since Symfony 5.4 + if ($container->has(RequestStack::class)) { + /** @var RequestStack $requestStack */ + $requestStack = $container->get(RequestStack::class); + + // see https://github.com/symfony/symfony-docs/pull/14898/files#diff-29ab32502d95be802fed1001850b76c9624912cf4c299101d3ecaf17b0352562R37 + try { + $session = $requestStack->getSession(); + } catch (SessionNotFoundException $e) { + $requestStack->push(new Request()); + $session = new Session(); + $session->start(); + } + + return $session; + } // Available before Symfony 6 if ($container->has(SessionInterface::class)) { - return $container->get(SessionInterface::class); + /** @var SessionInterface $session */ + $session = $container->get(SessionInterface::class); } - // For Symfony 4.4 - elseif ($container->has('session')) { - return $container->get('session'); + // Fallback for Symfony 4.4 + else { + /** @var \Symfony\Component\HttpFoundation\Session\Session $session */ + $session = $container->get('session'); } - throw new \Exception('Session is not available.'); + $session->start(); + + return $session; } } From 6f481c9976edb97408e5b30e2e4e8fe23933433c Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Thu, 19 May 2022 02:04:12 +0200 Subject: [PATCH 11/15] Since Symfony 6.0, UsernamePasswordToken only take 3 args --- src/Test/WebTestCase.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Test/WebTestCase.php b/src/Test/WebTestCase.php index bcc0384e..0dd9c7e8 100644 --- a/src/Test/WebTestCase.php +++ b/src/Test/WebTestCase.php @@ -343,6 +343,17 @@ protected function makeClientWithCredentials(string $username, string $password, */ protected function createUserToken(UserInterface $user, string $firewallName): TokenInterface { + // Since Symfony 6.0, UsernamePasswordToken only has 3 arguments + $usernamePasswordTokenClass = new \ReflectionClass(UsernamePasswordToken::class); + + if (3 === $usernamePasswordTokenClass->getConstructor()->getNumberOfParameters()) { + return new UsernamePasswordToken( + $user, + $firewallName, + $user->getRoles() + ); + } + return new UsernamePasswordToken( $user, null, From bb99098ad6f5a7ec8b348252ae0bedadeda28897 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Thu, 19 May 2022 02:13:35 +0200 Subject: [PATCH 12/15] Trigger deprecation on loginClient() and createClientWithParams() --- src/Test/WebTestCase.php | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/Test/WebTestCase.php b/src/Test/WebTestCase.php index 0dd9c7e8..d37a23c5 100644 --- a/src/Test/WebTestCase.php +++ b/src/Test/WebTestCase.php @@ -253,6 +253,9 @@ public function __call(string $name, $arguments) throw new \Exception("Method {$name} is not supported."); } + /** + * @deprecated + */ public function __set($name, $value): void { if ('environment' !== $name) { @@ -264,6 +267,9 @@ public function __set($name, $value): void static::$env = $value; } + /** + * @deprecated + */ public function __isset($name) { if ('environment' !== $name) { @@ -275,6 +281,9 @@ public function __isset($name) return true; } + /** + * @deprecated + */ public function __get($name) { if ('environment' !== $name) { @@ -429,6 +438,8 @@ public function fetchCrawler(string $path, string $method = 'GET', bool $authent } /** + * @deprecated + * * @return WebTestCase */ public function loginAs(UserInterface $user, string $firewallName): self @@ -444,8 +455,14 @@ public function loginClient(KernelBrowser $client, UserInterface $user, string $ { // Available since Symfony 5.1 if (method_exists($client, 'loginUser')) { - // TODO: on next minor release: - // trigger deprecation if Symfony ≥ 5.1 → https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication + @trigger_error( + sprintf( + '"%s()" is deprecated, use loginUser() from Symfony instead %s', + __METHOD__, + 'https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication' + ), + \E_USER_DEPRECATED + ); $client->loginUser($user); @@ -509,6 +526,9 @@ protected function tearDown(): void parent::tearDown(); } + /** + * @deprecated + */ protected function createClientWithParams(array $params, ?string $username = null, ?string $password = null): Client { if ($username && $password) { @@ -542,8 +562,14 @@ protected function createClientWithParams(array $params, ?string $username = nul // Available since Symfony 5.1 if (method_exists($client, 'loginUser')) { - // TODO: on next minor release: - // trigger deprecation if Symfony ≥ 5.1 → https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication + @trigger_error( + sprintf( + '"%s()" is deprecated, use loginUser() from Symfony instead %s', + __METHOD__, + 'https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication' + ), + \E_USER_DEPRECATED + ); $client->loginUser($user); From 6187b81a9f737f9ad37a12423295e690ec32ef1c Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Thu, 19 May 2022 02:26:16 +0200 Subject: [PATCH 13/15] Deprecate methods --- CHANGELOG.md | 8 ++++++++ src/Test/WebTestCase.php | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31da2485..9ab6379b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 5.0 + +## Removed + +## 4.6 + +Deprecated […] methods, use loginUser() from Symfony instead https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication + ## 4.0 ### Removed diff --git a/src/Test/WebTestCase.php b/src/Test/WebTestCase.php index d37a23c5..b2d7de65 100644 --- a/src/Test/WebTestCase.php +++ b/src/Test/WebTestCase.php @@ -301,6 +301,8 @@ public function __get($name) * $params can be used to pass headers to the client, note that they have * to follow the naming format used in $_SERVER. * Example: 'HTTP_X_REQUESTED_WITH' instead of 'X-Requested-With' + * + * @deprecated */ protected function makeClient(array $params = []): Client { @@ -313,6 +315,8 @@ protected function makeClient(array $params = []): Client * $params can be used to pass headers to the client, note that they have * to follow the naming format used in $_SERVER. * Example: 'HTTP_X_REQUESTED_WITH' instead of 'X-Requested-With' + * + * @deprecated */ protected function makeAuthenticatedClient(array $params = []): Client { @@ -331,6 +335,8 @@ protected function makeAuthenticatedClient(array $params = []): Client * $params can be used to pass headers to the client, note that they have * to follow the naming format used in $_SERVER. * Example: 'HTTP_X_REQUESTED_WITH' instead of 'X-Requested-With' + * + * @deprecated */ protected function makeClientWithCredentials(string $username, string $password, array $params = []): Client { @@ -451,6 +457,9 @@ public function loginAs(UserInterface $user, string $firewallName): self return $this; } + /** + * @deprecated + */ public function loginClient(KernelBrowser $client, UserInterface $user, string $firewallName): void { // Available since Symfony 5.1 From 122d254c733b5cde2a29f566369cf23cc2283875 Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Tue, 21 Jun 2022 22:28:20 +0200 Subject: [PATCH 14/15] session_*.yml: use imports to use less code --- tests/App/session.yml | 6 ++++++ tests/App/session_4.yml | 7 +++---- tests/App/session_5.yml | 7 +++---- 3 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 tests/App/session.yml diff --git a/tests/App/session.yml b/tests/App/session.yml new file mode 100644 index 00000000..28449678 --- /dev/null +++ b/tests/App/session.yml @@ -0,0 +1,6 @@ +framework: + session: + # handler_id set to null will use default session handler from php.ini + handler_id: ~ + # https://groups.google.com/forum/#!topic/symfony2/IB-CpMgo5o0 + name: MOCKSESSID diff --git a/tests/App/session_4.yml b/tests/App/session_4.yml index 929a36d1..19258079 100644 --- a/tests/App/session_4.yml +++ b/tests/App/session_4.yml @@ -1,7 +1,6 @@ +imports: + - session.yml + framework: session: - # handler_id set to null will use default session handler from php.ini - handler_id: ~ storage_id: session.storage.mock_file - # https://groups.google.com/forum/#!topic/symfony2/IB-CpMgo5o0 - name: MOCKSESSID diff --git a/tests/App/session_5.yml b/tests/App/session_5.yml index e0cbd8ef..c2147c1c 100644 --- a/tests/App/session_5.yml +++ b/tests/App/session_5.yml @@ -1,7 +1,6 @@ +imports: + - session.yml + framework: session: - # handler_id set to null will use default session handler from php.ini - handler_id: ~ storage_factory_id: session.storage.factory.mock_file - # https://groups.google.com/forum/#!topic/symfony2/IB-CpMgo5o0 - name: MOCKSESSID From 86c2e2b9543e98c68c3e5cfc4dc5c1e1d9abfdec Mon Sep 17 00:00:00 2001 From: Alexis Lefebvre Date: Tue, 21 Jun 2022 22:43:57 +0200 Subject: [PATCH 15/15] Update the CHANGELOG --- CHANGELOG.md | 14 ++++++++++++-- src/Test/WebTestCase.php | 34 ++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ab6379b..5e5b6189 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,21 @@ ## 5.0 -## Removed +Removed features deprecated in [4.6](#4.6) and [4.0](#4.0) + +## 4.7 + +Deprecations from [4.6](#4.6) will now trigger an `E_USER_DEPRECATED` deprecation ## 4.6 -Deprecated […] methods, use loginUser() from Symfony instead https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication +Deprecated the following methods, use [loginUser() from Symfony 5.1+](https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication) instead of: +- `makeClient` +- `makeAuthenticatedClient` +- `makeClientWithCredentials` +- `loginAs` +- `loginClient` +- `createClientWithParams` ## 4.0 diff --git a/src/Test/WebTestCase.php b/src/Test/WebTestCase.php index b2d7de65..13cbaf6a 100644 --- a/src/Test/WebTestCase.php +++ b/src/Test/WebTestCase.php @@ -464,14 +464,15 @@ public function loginClient(KernelBrowser $client, UserInterface $user, string $ { // Available since Symfony 5.1 if (method_exists($client, 'loginUser')) { - @trigger_error( - sprintf( - '"%s()" is deprecated, use loginUser() from Symfony instead %s', - __METHOD__, - 'https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication' - ), - \E_USER_DEPRECATED - ); + // TODO: enable this on the next minor release +// @trigger_error( +// sprintf( +// '"%s()" is deprecated, use loginUser() from Symfony 5.1+ instead %s', +// __METHOD__, +// 'https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication' +// ), +// \E_USER_DEPRECATED +// ); $client->loginUser($user); @@ -571,14 +572,15 @@ protected function createClientWithParams(array $params, ?string $username = nul // Available since Symfony 5.1 if (method_exists($client, 'loginUser')) { - @trigger_error( - sprintf( - '"%s()" is deprecated, use loginUser() from Symfony instead %s', - __METHOD__, - 'https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication' - ), - \E_USER_DEPRECATED - ); + // TODO: enable this on the next minor release +// @trigger_error( +// sprintf( +// '"%s()" is deprecated, use loginUser() from Symfony 5.1+ instead %s', +// __METHOD__, +// 'https://symfony.com/doc/5.4/testing.html#logging-in-users-authentication' +// ), +// \E_USER_DEPRECATED +// ); $client->loginUser($user);