browser icon indicating copy to clipboard operation
browser copied to clipboard

How to access Session variable

Open cooldude77 opened this issue 1 year ago • 6 comments

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

cooldude77 avatar May 27 '24 05:05 cooldude77

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

nikophil avatar May 27 '24 10:05 nikophil

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.

cooldude77 avatar May 27 '24 10:05 cooldude77

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

nikophil avatar May 27 '24 10:05 nikophil

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) {
    // ...
})

kbond avatar Jun 01 '24 17:06 kbond

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')
        ;
    }

hubertinio avatar Nov 08 '24 18:11 hubertinio

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!

mtnorthrop avatar Aug 04 '25 10:08 mtnorthrop