1

I am attempting to log a user in programmatically in my functional test on SF 2.7 and FOSUserBundle dev-master. I have already found a good reference to log a user in via SO in this answer - Symfony2 - Tests with FOSUserBundle

The problem is that the second answer, logging the user in programmatically, doesn't work. Here is my code:

<?php

namespace Test\BackEnd\UserBundle\Controller;

use Test\Shared\CoreBundle\Tests\AbstractControllerTest;
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Loader;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\Tools\SchemaTool;
use FA\BackEnd\UserBundle\DataFixtures\ORM\LoadUserData;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;

class DefaultController extends AbstractControllerTest
{

public function setUp()
{
    $this->client = static::createClient();

    $container = $this->client->getContainer();

    $doctrine = $container->get('doctrine');
    $em = $doctrine->getManager();
    $schemaTool = new SchemaTool($em);
    $metadata = $em->getMetaDataFactory()->getAllMetadata();

    // Drop and recreate tables for all entities
    $schemaTool->dropSchema($metadata);
    $schemaTool->createSchema($metadata);

    $loader = new Loader();
    $user = new LoadUserData();
    $user->setContainer($container);
    $loader->addFixture($user);

    $purger = new ORMPurger();
    $executor = new ORMExecutor($em, $purger);
    $executor->execute($loader->getFixtures());

    $session = $container->get('session');
    $userManager = $container->get('fos_user.user_manager');

    $user = $userManager->findUserBy(array('username' => 'test'));

    $firewall = 'default';

    $token = new UsernamePasswordToken($user, $user->getPassword(), $firewall, $user->getRoles());
    self::$kernel->getContainer()->get('security.token_storage')->setToken($token);
    $session->set('_security_'.$firewall, serialize($token));
    $session->save();

    $cookie = new Cookie($session->getName(), $session->getId());
    $this->client->getCookieJar()->set($cookie);
}

public function testProfile()
{
    //$this->createAuthorizedClient();

    $token = $this->client->getContainer()->get('security.token_storage')->getToken();

    $this->client->request('GET', '/profile/');

    $this->assertEquals(
        200,
        $this->client->getResponse()->getStatusCode(),
        "/profile isn't accessible"
    );

}
}

Whenever I set a break point before the route gets executed, the token is return correctly: PHPStorm Xdebug Output for token

Whenever I get to the function getUser() used by the Controller (http://api.symfony.com/2.7/Symfony/Bundle/FrameworkBundle/Controller/Controller.html#method_getUser) PHPStorm returns an empty token as viewed here:

PHPstorm Xdebug Information null token

So I decided to try the following code to log a user in, and it works.

    $crawler = $this->client->request('GET', '/login');

    $form = $crawler->selectButton('_submit')->form(array(
        '_username'  => 'test',
        '_password'  => 'test123',
    ));

    $this->client->submit($form);
    $this->client->followRedirect(); 

Am I not doing something properly whenever I log the user in programmatically? Is the session not being set properly?

Thanks!

Rat

Community
  • 1
  • 1
Ratty
  • 436
  • 1
  • 7
  • 19
  • the only thing I can see thats different to how I do it is that your calling the container again. I wonder if its out of scope for some reason. Try storing the container in a class private member at the start and call it from there. – DevDonkey Oct 16 '15 at 14:32
  • Good point. I corrected that and added: $container->get('security.token_storage')->setToken($token); Althought, that didn't seem to fix it. Interesting. – Ratty Oct 16 '15 at 19:14
  • Did you try to create a BaseTest that log the user? And you can always get the client from the logged user client instance. So you don't need to log in every test. – Iago Oct 18 '15 at 04:32

1 Answers1

0

I use this:

protected function createAuthorizedClient()
    {
     $client = static::createClient();
     $container = $client->getContainer();

     $session = $container->get('session');
     $userManager = $container->get('fos_user.user_manager');
     $loginManager = $container->get('fos_user.security.login_manager');
     $firewallName = $container->getParameter('fos_user.firewall_name');

     $user = $userManager->findUserBy(array('username' => 'USERNAME'));
     $loginManager->loginUser($firewallName, $user);

     // save the login token into the session and put it in a cookie
     $container->get('session')->set('_security_' . $firewallName, 
     serialize($container->get('security.context')->getToken()));
     $container->get('session')->save();
     $client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
     $this->client = $client;
}

and then in your test:

public function testMiInfo()
{
    $this->createAuthorizedClient();
    //else..
}
Roberto
  • 532
  • 7
  • 20
  • which you found here, I guess... https://advancingusability.wordpress.com/2013/11/15/functional-testing-with-authentication-and-symfony-2-3-fosuserbundle/ – mika Nov 09 '15 at 15:27