How to access Session variable
Hi, For testing purposes , I need to access session and set a value to it .
The class Browser has marked session as protected . I could not find in documentation any reference to session in any method
Thanks
hello @cooldude77
by "session", do you mean "http session"? Browser does not deal with http session. And the method Browser::session() refers do the "mink session" which is a different concept
Hey @nikophil ,
Sorry for not explaining it fully.
I wish to test how controller logic behave when I set a session variable ( for eg. a filled cart in a web shop or an empty cart).
Here I would like to set the session variable which I access in controller using RequestStack getRequest() method in my controller method and then getting the session from it. Based on values in session, controller performs a logic.
I understand that the browser does not have session because it is handled by Mink. Will that be the same session as I explained above and can I manipulate it somewhere in test case ?
Thanks.
currently, browser does not provide a way to manipulate the session. Maybe this could be a nice addition to this lib? ping @kbond
For now, maybe you could use this trick: https://github.com/symfony/symfony/discussions/45662#discussioncomment-4352880
Yes, this would be a nice addition.
You can currently access the "cookie jar":
$browser->use(CookieJar $cookies) {
// ...
})
I use it successfully to expire the current session:
$browser->use(function(CookieJar $cookieJar) {
$cookieJar->expire('MOCKSESSID');
})
It would be nice if we could do the following:
$browser->use(SessionInterface $session) {
// ...
})
Maybe you can create correct session variables "one step before". This is integration tests...
For example CartControllerTest
public function test_list_items(): void
{
$user = UserFactory::createOne();
$product = ProductFactory::randomOrCreate();
$product2 = ProductFactory::randomOrCreate();
$productPageUrl = '/product/' . $product->id();
$productPageUrl2 = '/product/' . $product->id();
$this->browser()
->actingAs($user)
->interceptRedirects()
->visit($productPageUrl)
->assertSuccessful()
->click('Add to cart')
->visit($productPageUrl2)
->assertSuccessful()
->click('Add to cart')
->assertRedirectedTo('/cart')
->assertSuccessful()
->assertSee($product->_real()->getName())
->assertSee($product2->_real()->getName())
->assertSee('Product added to cart')
->assertSeeIn('btn-primary', 'Order')
;
}
I found a way to modify session data in tests where I'm using the KernelBrowser, and with framework.session.storage_factory_id set to session.storage.factory.mock_file. The comment referenced above (https://github.com/symfony/symfony/discussions/45662#discussioncomment-4352880) helped me find a solution that works with Zenstruck's KernelBrowser.
In my case, I was trying to find a way of setting a CSRF token in the session so that I can test controller actions that try to verify post data that includes a token.
This is what worked for me:
public function testSetSessionData()
{
$this->browser()
->use(function(\Symfony\Component\BrowserKit\CookieJar $cookieJar, \Symfony\Component\BrowserKit\AbstractBrowser $browser) use ($sessionItemName, $sessionItemValue) {
$cookie = $cookieJar->get('MOCKSESSID');
$session = $browser->getContainer()->get('session.factory')->createSession();
if ($cookie) {
$session->setId($cookie->getValue());
} else {
$session->start();
$sessionCookie = new Cookie(
$session->getName(),
$session->getId(),
null,
null,
'localhost',
);
$cookieJar->set($sessionCookie);
}
$session->set($sessionItemName, $sessionItemValue);
$session->save();
});
}
This approach worked for my use-case, but I can't guarantee it will work for everyone. One important thing to note is that $browser->actingAs() calls Symfony\Bundle\FrameworkBundle::loginUser(), which creates a new session and cookie with a new ID, so, if you're using $browser->actingAs(), you have to make sure to set your session data after calling actingAs().
Hope this helps!