Symfony2 functional test Unreachable field "_token"

1.2k Views Asked by At

I am creating a functional test in Symfony using the Liip functional test bundle.

I am currently stuck on submiting an form.
I am trying to add a new 'log' using the functional test.

If I try to add a new log trough the UI I get the following request parameters:

'WorkLog' => array(
    'submit' => '',
    'hours' => '8',
    'minutes' => '0',
    'note' => 'some text',
    '_token' => '4l5oPcdCRzxDKKlJt_RG-B1342X52o0C187ZLLVWre4' 
);

But when the test submits the form I get the same parameters but without the token

 'WorkLog' => array(
    'submit' => '',
    'hours' => '8',
    'minutes' => '0',
    'note' => 'some text'
);

I thought I could fix the problem by adding the '_token' field to the form request, but when I ran then test again it gave me an error:

InvalidArgumentException: Unreachable field "_token"

The code of the functional test:

namespace App\AdminBundle\Tests\Controller;

use Liip\FunctionalTestBundle\Test\WebTestCase;

use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\BrowserKit\Cookie;

class LogControllerTest extends WebTestCase
{
    private $client;
    private $em;
    private $fixtures;

    public function setUp()
    {
        $this->client = static::makeClient();
        $this->em = $this->client->getContainer()->get('doctrine')->getManager();

        $this->fixtures = $this->loadFixtures(array(
            'App\AdminBundle\DataFixtures\ORM\LoadUserData',
            'App\AdminBundle\DataFixtures\ORM\LoadSubscriptionTypesData',
            'App\AdminBundle\DataFixtures\ORM\LoadSubscriptionData',
            'App\AdminBundle\DataFixtures\ORM\LoadWorkLogData',
        ))->getReferenceRepository();
    }

    public function testAddNewLog()
    {
        $accountId = $this->fixtures->getReference('userAccount')->getId();

        // log in with admin account
        $this->logIn('adminAccount');

        $crawler = $this->client->request('GET', '/admin/worklog/account/'.$accountId.'/add');
        $csrfToken = $this->client->getContainer()->get('form.csrf_provider')->generateCsrfToken('post_type');

        $form = $crawler->selectButton('WorkLog_submit')->form(array(
            'WorkLog' => array(
                'hours' => '8',
                'minutes' => '0',
                'note' => 'some text',
                '_token' => $csrfToken
            ),
        ), 'POST');

        $crawler = $this->client->submit($form);
    }
}

My question: How can I submit the form with the token?

2

There are 2 best solutions below

4
On BEST ANSWER

I don't work with the Liip Functional Test Bundle, but I usually work with form and _token in the following manner:

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

    // retrieves the form token
    $token = $crawler->filter('[name="select_customer[_token]"]')->attr("value");

    // makes the POST request
    $crawler = $this->client->request('POST', $url, array(
        'select_customer' => array(
            '_token' => $token,
            'customerId' => $customerId,
        ),
    ));

Hope this helps.

0
On

I encountered a very similar problem for a few hours... My method was a little different. When I was asking some help, Stackoverflow has detected a possible duplicate and I found your question. Your question help me to answer our similar problems.

You're doing that :

    $form = $crawler->selectButton('WorkLog_submit')->form(array(
        'WorkLog' => array(
            'hours' => '8',
            'minutes' => '0',
            'note' => 'some text',
            '_token' => $csrfToken
        ),
    ), 'POST');

You tried to do it in one step. But it is not possible because Liip functional bundle is trying to set array of array with some magic method and it crashes. I understood that we have to do it with more steps :

I use it in my code like that (you can see that I am no more using Liip bundle):

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class GameControllerTest extends WebTestCase
{
    public function testLoadGame(){


        $client = static::createClient();
        $crawler = $client->request('GET', '/loadGame');
        $form = $crawler->selectButton('Load')->form();
        $field = $form->get("load[uuid]");
        $field->setValue($uuid1[0]);
        $form->set($field);
        $client->submit($form);
        $response = $client->getResponse();
        self::assertTrue($response->isRedirect('/game'));

    }
}

So I think that the solution for your problem is :

    $form = $crawler->selectButton('WorkLog_submit')->form();        
    //dump($form) //uncomment this line to have a look on the array of array
    $fieldToken = $form->get("WorkLog[_token]");
    $fieldToken->setValue($csrfToken);
    $form->set($fieldToken);
    $client->submit($form);