Skip to content

Commit 972f721

Browse files
committed
feature #61110 [FrameworkBundle] Prepare session in functionnal tests (cyve)
This PR was merged into the 7.4 branch. Discussion ---------- [FrameworkBundle] Prepare session in functionnal tests | Q | A | ------------- | --- | Branch? | 7.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | Fix #46023 | License | MIT | Doc PR | symfony/symfony-docs#21352 | Hello, I propose to add a `getSession()` method to the `KernelBrowser` class to be able to prepare the session before sending a HTTP request in a functionnal test. It could be used to preset CSRF tokens, A/B testing data, user preferences, or any stateful information required for the test. I also propose to use `getSession()` in the `loginUser()` method. Then, the session could be preset either before or after the login, without risking to be overwritten. ```php public function testForm() { $client = self::createClient(); $client->loginUser(new InMemoryUser('admin', null)); $session = $client->getSession(); $session->set('_csrf/form', '123456789'); $session->set('foo', 'bar'); $session->save(); $client->request('POST', '/form', ['form' => ['_token' => '123456789']]); } ``` In this example, the session will contain : ```php array:3 [ "_security_main" => "O:52:"Symfony\Bundle\FrameworkBundle\Test\TestBrowserToken":2:{i:0;s:4:"main";i:1;a:5:{i:0;O:49:"Symfony\Component\Security\Core\User\InMemoryUser":4:{s:59:"\x00Symfony\Component\Security\Core\User\InMemoryUser\x00username";s:5:"admin";s:59:"\x00Symfony\Component\Security\Core\User\InMemoryUser\x00password";N;s:56:"\x00Symfony\Component\Security\Core\User\InMemoryUser\x00roles";a:0:{}s:58:"\x00Symfony\Component\Security\Core\User\InMemoryUser\x00enabled";b:1;}i:1;b:1;i:2;N;i:3;a:0:{}i:4;a:0:{}}}", "_csrf/form" => "123456789", "foo" => "bar" ] ``` Thanks in advance for your feedbacks 😄 Commits ------- a8f045fdbcb [FrameworkBundle] Add KernelBrowser::getSession()
2 parents 9d9f8e3 + 9a8e9e4 commit 972f721

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ CHANGELOG
1010
* Deprecate `Symfony\Bundle\FrameworkBundle\Console\Application::add()` in favor of `Symfony\Bundle\FrameworkBundle\Console\Application::addCommand()`
1111
* Add `assertEmailAddressNotContains()` to the `MailerAssertionsTrait`
1212
* Add `framework.type_info.aliases` option
13+
* Add `KernelBrowser::getSession()`
1314

1415
7.3
1516
---

KernelBrowser.php

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\DependencyInjection\ContainerInterface;
1919
use Symfony\Component\HttpFoundation\Request;
2020
use Symfony\Component\HttpFoundation\Response;
21+
use Symfony\Component\HttpFoundation\Session\SessionInterface;
2122
use Symfony\Component\HttpKernel\HttpKernelBrowser;
2223
use Symfony\Component\HttpKernel\KernelInterface;
2324
use Symfony\Component\HttpKernel\Profiler\Profile as HttpProfile;
@@ -63,6 +64,35 @@ public function getProfile(): HttpProfile|false|null
6364
return $this->getContainer()->get('profiler')->loadProfileFromResponse($this->response);
6465
}
6566

67+
public function getSession(): ?SessionInterface
68+
{
69+
$container = $this->getContainer();
70+
71+
if (!$container->has('session.factory')) {
72+
return null;
73+
}
74+
75+
$session = $container->get('session.factory')->createSession();
76+
77+
$cookieJar = $this->getCookieJar();
78+
$cookie = $cookieJar->get($session->getName());
79+
80+
if ($cookie instanceof Cookie) {
81+
$session->setId($cookie->getValue());
82+
}
83+
84+
$session->start();
85+
86+
if (!$cookie instanceof Cookie) {
87+
$domains = array_unique(array_map(fn (Cookie $cookie) => $cookie->getName() === $session->getName() ? $cookie->getDomain() : '', $cookieJar->all())) ?: [''];
88+
foreach ($domains as $domain) {
89+
$cookieJar->set(new Cookie($session->getName(), $session->getId(), domain: $domain));
90+
}
91+
}
92+
93+
return $session;
94+
}
95+
6696
/**
6797
* Enables the profiler for the very next request.
6898
*
@@ -116,20 +146,13 @@ public function loginUser(object $user, string $firewallContext = 'main', array
116146
$container = $this->getContainer();
117147
$container->get('security.untracked_token_storage')->setToken($token);
118148

119-
if (!$container->has('session.factory')) {
149+
if (!$session = $this->getSession()) {
120150
return $this;
121151
}
122152

123-
$session = $container->get('session.factory')->createSession();
124153
$session->set('_security_'.$firewallContext, serialize($token));
125154
$session->save();
126155

127-
$domains = array_unique(array_map(fn (Cookie $cookie) => $cookie->getName() === $session->getName() ? $cookie->getDomain() : '', $this->getCookieJar()->all())) ?: [''];
128-
foreach ($domains as $domain) {
129-
$cookie = new Cookie($session->getName(), $session->getId(), null, null, $domain);
130-
$this->getCookieJar()->set($cookie);
131-
}
132-
133156
return $this;
134157
}
135158

Tests/Functional/SessionTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ public function testWelcome($config, $insulate)
4545
// prove cleared session
4646
$crawler = $client->request('GET', '/session');
4747
$this->assertStringContainsString('You are new here and gave no name.', $crawler->text());
48+
49+
// prepare session programatically
50+
$session = $client->getSession();
51+
$session->set('name', 'drak');
52+
$session->save();
53+
54+
// ensure session can be saved multiple times without being reset
55+
$session = $client->getSession();
56+
$session->set('foo', 'bar');
57+
$session->save();
58+
59+
// prove remembered name from programatically prepared session
60+
$crawler = $client->request('GET', '/session');
61+
$this->assertStringContainsString('Welcome back drak, nice to meet you.', $crawler->text());
4862
}
4963

5064
/**

0 commit comments

Comments
 (0)