Search code examples
functional-testingsilex

How to simulate authenticated users in functional tests in Silex php framework


I am trying to functional test a page protected by authentication form.

My code is based on this link: http://symfony.com/doc/current/testing/simulating_authentication.html

But it still does not work for me.

Here is thye error message that I get:

PHP Fatal error:  Call to undefined method Symfony\Component\HttpKernel\Client::getContainer()

Here is my code:

class ClientTest extends WebTestCase {

    public function createApplication()
    {
        return require __DIR__.'/../app.php';
    }

    /**
     * @test
     */
    public function index_when_no_clients()
    {
        $this->client = $this->createClient();
        $crawler = $this->client->request('GET', '/');

        $this->assertTrue($this->client->getResponse()->isOk());
        $this->assertCount(1, $crawler->filter('h1:contains("Clients")'));
        $this->assertCount(1, $crawler->filter('span[class="glyphicon glyphicon-plus"]'));
    }

    /**
     * @test
     */
    public function add_get_route_is_valid()
    {
        $client = $this->createClient();
        $session = $client->getContainer()->get('session');

        // the firewall context (defaults to the firewall name)
        $firewall = 'secured_area';

        $token = new UsernamePasswordToken('admin', null, $firewall, array('ROLE_ADMIN'));
        $session->set('_security_'.$firewall, serialize($token));
        $session->save();

        $cookie = new Cookie($session->getName(), $session->getId());
        $client->getCookieJar()->set($cookie);
        $crawler = $client->request('GET', '/add'); 

        $this->assertTrue($client->getResponse()->isOk());
    }   
}

Here is how I am setting authentication in my index.php:

$app->register(new \Silex\Provider\SessionServiceProvider(), [
    'session.test' => 'test' === $app['env'],
]);
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
    'security.firewalls' => array(
        'admin' => array(
            'pattern' => '^/add',
            'form' => array('login_path' => '/login', 'check_path' => '/add/login_check'),
            'users' => $app->share(function() use ($app) {
                $config = Configuration::getInstance();
                $pdoQueries = new PdoQueries(PdoConnection::getInstance($config));
                return new UserProvider($pdoQueries);
            }),
        ),
    )
));

$app->get('/login', function(Request $request) use ($app, $arrConfig) {
    return $app['twig']->render('auth/form.twig', array(
            'error'         => $app['security.last_error']($request),
            'last_username' => $app['session']->get('_security.last_username'),
            'title'         => 'Login',
            'assetsUrl'             => $arrConfig['assets_url']
    ));
});

And here is the content of the app.php called in createApplication:

<?php
require __DIR__ ."/../www/index.php";
unset($app['exception_handler']);
return $app;

Thanks


Solution

  • I found the problem and the solution.

    The problem was the getContainer statement. Dependency injection is called in a different way in silex. just calling

    $app['session']
    

    directly solved the problem.

    Here is the full script with the symfony classes to import as well.

    <?php 
    use Silex\WebTestCase;
    use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
    use Symfony\Component\BrowserKit\Cookie;
    
    class ClientTest extends WebTestCase {
    
        public function createApplication()
        {
            return require __DIR__.'/../app.php';
        }
    
        private function logIn($client)
        {
            $session = $this->app['session'];
            $firewall = 'admin';
            $token = new UsernamePasswordToken('admin', null, $firewall, array('ROLE_ADMIN'));
            $session->set('_security_'.$firewall, serialize($token));
            $session->save();
            $cookie = new Cookie($session->getName(), $session->getId());
            $client->getCookieJar()->set($cookie);
    
            return $client;
        }   
    
        /**
         * @test
         */
        public function index_when_no_clients()
        {
            $this->client = $this->createClient();
            $crawler = $this->client->request('GET', '/');
    
            $this->assertTrue($this->client->getResponse()->isOk());
            $this->assertCount(1, $crawler->filter('h1:contains("Clients")'));
            $this->assertCount(1, $crawler->filter('span[class="glyphicon glyphicon-plus"]'));
        }
    
        /**
         * @test
         */
        public function add_get_route_is_valid()
        {
            $client = $this->createClient();
            $client = $this->logIn($client);
            $crawler = $client->request('GET', '/add'); 
    
            $this->assertTrue($client->getResponse()->isOk());
        }   
    
    }
    

    Hope that will help other people.