symfony2 test flashbag or session data - symfony

How do you test for FlashBag message?
Tried this:
public function testInvalidLogin()
{
$session = $this->client->getContainer()->get('session');
$crawler = $this->client->request('GET', '/login');
$this->assertTrue($this->client->getResponse()->isSuccessful());
$form = $crawler->filter('form');
$this->assertGreaterThan(0, $form->count());
$form = $form->form();
$this->assertNotEmpty($form);
$form['_username'] = 'username';
$form['_password'] = 'password';
$this->client->submit($form);
$this->assertTrue($this->client->getResponse()->isRedirect('http://localhost/login'));
$this->client->followRedirect();
$session = $this->client->getContainer()->get('session');
var_dump($session->getBag('flashes')->all()); // this print an empty array
}
The login controller is sets a flash message 'Bad credentials' but i'm not able to see it during the tests.

Probably it's because after your redirection you are poping flash message eg. somewhere in your template. Flash bag container remove flash message just after you call get method (to be specified - removing is implemented IN get method...). If you want just get the message without poping it you should use peek method.
I guess that if you move var_dump before followRedirect then you will get the result you are expecting.

Related

Symfony test get form errors

If I have a functional test like:
public function testCreate()
{
$client = $this->makeClient();
$crawler = $client->request('POST', "/post/new");
$form = $crawler->selectButton("Create Post")->form();
$values = $form->getPhpValues();
$values['post']['title'] = 'test';
$values['post']['content'] = null; // Should fail because it isn't a string.
$crawler = $client->request($form->getMethod(), $form->getUri(), $values,
$form->getPhpFiles());
assertEquals() // What goes here?
}
How do I use the crawler to get the form errors and compare them?
I see two possible solutions for you:
Use the crawler to check for the actually rendered form errors in your rendered HTML code.
Make use of the profiler and access the form data collector: http://symfony.com/doc/current/testing/profiling.html

Delete test entity after testing with phpunit symfony

When I test an entity it creates it in the database but I can't manage to delete it. I think I have the default code to delete the entity but it does not work, is there another way? am I missing something?
Here is the code. I'm using symfony 2.7.8 and Php unit 4.8.0
public function testCreateCurso()
{
// Create a new client to browse the application
$client = static::createAuthorizedClient();
// Create a new entry in the database
$crawler = $client->request('GET', '/admin/curso/');
$this->assertEquals(200, $client->getResponse()->getStatusCode(), 'Unexpected HTTP status code for GET /curso/');
$crawler = $client->click($crawler->selectLink('Crear Nuevo Curso')->link());
// Fill in the form and submit it
$form = $crawler->selectButton('Create')->form(array(
'appbundle_curso[nombreCurso]' => 'Test',
'appbundle_curso[codigoCurso]' => 'Test4',
// ... other fields to fill
));
$client->submit($form);
$this->assertTrue($client->getResponse()->isRedirect());
$crawler = $client->followRedirect();
// Check data in the show view
$this->assertGreaterThan(0, $crawler->filter('td:contains("Test")')->count(), 'Missing element td:contains("Test")');
// Edit the entity
$crawler = $client->click($crawler->selectLink('Editar')->link());
$form = $crawler->selectButton('Update')->form(array(
'appbundle_curso[nombreCurso]' => 'Foo',
'appbundle_curso[codigoCurso]' => 'Foo1',
// ... other fields to fill
));
$client->submit($form);
//
$crawler = $client->followRedirect();
// Check the element contains an attribute with value equals "Foo"
$this->assertGreaterThan(0, $crawler->filter('[value="Foo"]')->count(), 'Missing element [value="Foo"]');
// Delete the entity
$client->submit($crawler->selectButton('Delete')->form());
$crawler = $client->followRedirect();
// Check the entity has been delete on the list
$this->assertNotRegExp('/Foo/', $client->getResponse()->getContent());
var_dump($client->getResponse()->getContent());
}
This code is actually showing us how you test the UI, but the real code that is actually deleting the entity...
So, you should first of all check that both scenarios (adding an entity and deleting it) are actually working properly with unit tests (maybe when deleting the entity you're not flushing changes, for example...).
Then, when you have demonstrated yourself that you can actually add and delete the entity, and the controllers are working, then you should test your user interface, and that's what you're showing us.
So, if you've already done this, the issue is on your UI (for example, your button can't be followed).
Maybe a little bit more of information?
I was missing this method to delete the entity from the database
/**
* Close doctrine connections to avoid having a 'too many connections'
* message when running many tests
*/
public function tearDown(){
parent::tearDown();
}

Symfony2 error Flushing an entitiy within the preUpdate event of another entiity

I have a reletivly simple change logging class that stores the date, an integer to indicate the type of change and 2 varchar(50)s that hold the old and new data for the change.
I can create and populate an instance of the class but when I come to flush it I get an "Error: Maximum function nesting level of '200' reached, aborting!" error.
I've read about the Xdebug issue and configured the max nests up to 200 but as you can see this isn't enough. The save process should be very simple and there should be no need for so many nested functions, so increasing it further will just hide the problem, whatever it is. I have far more complicated classes in this app that persisit and flush without a problem.
The issue is always at
NormalizerFormatter ->normalize ()
in app/cache/dev/classes.php at line 4912 -
Having looked at this a bit more I think the issue may be that the change instance is created and saved during the preUpdate event of another class:
public function preUpdate(LifecycleEventArgs $eventArgs)
{
$entity = $eventArgs->getEntity();
if ($entity instanceof Property) {
$entityManager = $eventArgs->getEntityManager();
$changeArray = $eventArgs->getEntityChangeSet();
foreach ($changeArray as $field => $values) {
$eventType = "";
switch ($field) {
case 'price' :
$eventType = PropertyEvent::EVENTTYPE_PRICE;
BREAK;
case 'status' :
$eventType = PropertyEvent::EVENTTYPE_STATUS;
BREAK;
}
if ($eventType != "") {
$event = new PropertyEvent($entity->getID(), $eventType, $values[0], $values[1]);
$entityManager->persist($event);
$entityManager->flush();
}
}
$entity->setUpdatedDate();
}
}
Why would that be an issue?
Doctrine only has one lifecycle event process so regardless of the entity you're using adding a flush within a lifecycle event will send you back round the loop and into your event handler again... and again ... and...
Have a look at this blog post
http://mightyuhu.github.io/blog/2012/03/27/doctrine2-event-listener-persisting-a-new-entity-in-onflush/
Basically the answer is to use
$eventManager -> removeEventListener('preUpdate', $this);
to remove the event. Then create the new entity, persist, flush and finally re-attach the event you are in.
$eventManager -> addEventListener('preUpdate', $this);
I think your issue is the $entity->setUpdatedDate(); call, which probably calls another update event and re-calls your handler.

CSRF Token from the controller

I have a controller getting a form posted.
public function myPostAction(Request $request)
{
$form = $this->createForm('my_form', $my_object);
$form->handleRequest($request);
#...
I can see my CSRF token posted as parameter
my_form[_token] => lH38HTm5P0Cv3TOc4-9xi2COx-cZ670mpJ_36gR8ccI
I simply need to read it
$form->get('_token')
This tells me
Child "_token" does not exist.
How can I get this token ?
Here is the workaround I'm going to use meanwhile:
$token = $request->get($form->getName())['_token'];
I also noticed by chance that the intention used to generate the token is the form name
$csrf = $this->get('form.csrf_provider');
$intention = $form->getName();
$token = $csrf->generateCsrfToken($intention);
Like #Pierre de LESPINAY said, it is possible to do it by retrieving Token Manager service.
This service can also be injected in your constructor like that :
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
...
public function __construct(CsrfTokenManagerInterface $tokenManager)
{
$this->tokenManager = $tokenManager;
}
And used later like previously demonstrated :
$token = $this->tokenManager->getToken('myformname')->getValue();
You can get it with:
$request->request->get('my_form[_token]');
If you didn't disable CSRF-protection it will be applied and validated automatically and you don't need to check it by self.

Symfony 2 - Adding session data to request object during unit testing

I'm trying to set up some testing for my REST API and I need to set a session variable inside the request object. The usual methods do not seem to work.
$session = $request->getSession();
$session->set('my_session_variable', 'myvar');
You should use WebTestCase
Then you can do things which are described in answer for similar question: how-can-i-persist-data-with-symfony2s-session-service-during-a-functional-test
so something like:
$client = static::createClient();
$container = $client->getContainer();
$session = $container->get('session');
$session->set('name', 'Sensorario');
$session->save();
If you use WebTestCase, you can retrieve the "session" service.
With this service, you can :
start the session,
set some parameters into session,
save the session,
pass the Cookie with sessionId to the request
The code can be the following :
use Symfony\Component\BrowserKit\Cookie;
....
....
public function testARequestWithSession()
{
$client = static::createClient();
$session = $client->getContainer()->get('session');
$session->start(); // optional because the ->set() method do the start
$session->set('my_session_variable', 'myvar'); // the session is started here if you do not use the ->start() method
$session->save(); // important if you want to persist the params
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId())); // important if you want that the request retrieve the session
$client->request( .... ...
A short snippet to set some value in session
$session = $this->client->getRequest()->getSession();
$session->set('name', 'Sensorario');
And a very very simple example to get this value
echo $session->get('name');

Resources