How to submit form in PHPunit with symfony? - phpunit

I am using symfony 3.0 and phpunit 3.7.1.I want to submit a form via phpunit file.
File Name: abcControllerTest.php
<?php
namespace AbcBundle\Tests\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\Request;
class AbcControllerTest extends WebTestCase {
public function testEmpty() {
$whereParams = array('params' => array(
'var' => '',
));
return $whereParams;
}
/**
* ABC Builder
* #depends testEmpty
*/
public function testAbc(array $whereParams) {
$client = static::createClient();
$crawler = $client->request('GET', $GLOBALS['host'] . '/abc/ac_file/param', $whereParams);
$buttonCrawlerNode = $crawler->selectButton('Submit');
$form = $buttonCrawlerNode->form();
$crawler = $client->submit($form);
}
}
I am testing export report functionality thats why i am just creating a submit button and trying to submit form on specific url with some parameter.
Error Message: InvalidArgumentException: The current node list is empty.
Anyone can suggest me what can i do?

Related

Convert POST Request to Doctrine Entity

Coming from a NodeJS environment, this seems like a nobrainer but I somehow did not figured it out.
given the function:
/**
* #Route("/", name="create_stuff", methods={"POST"})
*/
public function createTouristAttraction($futureEntity): JsonResponse
{
...
}
Let futureEntity have the same structure as my PersonEntity.
What is the best way of mapping that $futureEntity to a PersonEntity?
I tried to assign it manually, and then run my validations which seems to work, but i think this is cumbersome if a model has more than 30 fields...
Hint: Im on Symfony 4.4
Thank you!
Doc: How to process forms in Symfony
You need to install the Form bundle: composer require symfony/form (or composer require form if you have the Flex bundle installed)
Create a new App\Form\PersonType class to set the fields of your form and more: doc
In App\Controller\PersonController, when you instanciate the Form, just pass PersonType::class as a first parameter, and an new empty Person entity as a second one (the Form bundle will take care of the rest):
$person = new Person();
$form = $this->createForm(PersonType::class, $person);
The whole controller code:
<?php
namespace App\Controller;
use App\Entity\Person;
use App\Form\PersonType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class PersonController extends AbstractController
{
private $entityManager;
public function __construct(EntityManagerInterface $entityManager) {
$this->entityManager = $entityManager;
}
/**
* #Route("/person/new", name="person_new")
*/
public function new(Request $request): Response
{
$person = new Person(); // <- new empty entity
$form = $this->createForm(PersonType::class, $person);
// handle request (check if the form has been submited and is valid)
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$person = $form->getData(); // <- fill the entity with the form data
// persist entity
$this->entityManager->persist($person);
$this->entityManager->flush();
// (optional) success notification
$this->addFlash('success', 'New person saved!');
// (optional) redirect
return $this->redirectToRoute('person_success');
}
return $this->renderForm('person/new.html.twig', [
'personForm' => $form->createView(),
]);
}
}
The minimum to display your form in templates/person/new.html.twig: just add {{ form(personForm) }} where you want.

FOSuserBundle override controller

What is the right way to pass more variables to FOSUserBundle settings twig template (Profile/show_content.html.twig) in Symfony 3.4?
I basically want to rewrite showAction() method and pass more than user variable ti twig template.
I tried to following this tutorial. It seems it does no longer work with Symfony 3.4
The way I do it (and there might be better methods) is simply create a new controller with a route to the original 'show route', together with the variables I want to pass. Here is an example of the showAction() with an extra variable rendered_address:
namespace App\Controller;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class ProfileController extends Controller
{
/**
* Show the user.
* #Route("/profile/show")
*/
public function showAction()
{
$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
$address = $this->getUser()->renderAddress(); // here is get my variable
return $this->render('#FOSUser/Profile/show.html.twig', array(
'user' => $user,
'rendered_address' => $address // here is pass my variable
));
}
}

PHPUnit + Symfony : Loop when trying to log in

I'm trying to authenticate with a form_login through one test but after submitted the form it redirect to /login.
Symfony : 4.0.4, FOSUserBundle : 2.1.1
Does anynone have a clue ? (credentials and selectButton are ok)
<?php
namespace App\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class CompanyControllerTest extends WebTestCase
{
/** #test */
public function companyDefaultAction_isWorking()
{
$client = static::createClient();
$crawler = $client->request('GET', '/login');
$form = $crawler->selectButton('Connexion')->form(array(
'_username' => '...',
'_password' => '...',
));
$client->submit($form);
$crawler = $client->followRedirect();
}
}
Forgot to define the environment variables for the test environment in phpunit.xml.dist :
<env name="DATABASE_URL" value="mysql://root:#127.0.0.1:3306/dbname" />

Symfony unit testing & the container

When unit testing in Symfony 2, the controller I'm testing does not receive the service container causing the test to fail with the good old Call to a member function get() on a non-object
I can't use $this->forward from the testing controller as it also does not have the service container.
I found this reference but it seems as though I would be using it for the wrong reason, has anyone had any experience with this?
http://symfony.com/doc/current/book/testing.html#accessing-the-container
Edit: Here is my test:
<?php
namespace HvH\ClientsBundle\Tests\Controller;
use HvH\ClientsBundle\Controller\ClientsController;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\HeaderBag;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class ClientsControllerTest extends WebTestCase
{
public function testGetClientsAction()
{
$client = static::createClient();
$container = $client->getContainer();
$session = $container->get('session');
$session->set('key', 'value');
$session->save();
$request = new Request;
$request->create('/clients/123456', 'GET', array(), array(), array(), array(), '');
$headers['X-Requested-With'] = "XMLHttpRequest";
$request->headers->add($headers);
/* This doesn't work */
/*
$controller = new Controller;
$status = $controller->forward( 'HvHClientsBundle:Clients:getClients', array('request' => $request) );
*/
$clients_controller = new ClientsController();
$status = $clients_controller->getClientsAction($request);
$this->assertEquals(200, $status);
}
}
Here is the part of the clients controller where it fails
<?php
namespace HvH\ClientsBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use HvH\APIschemaBundle\Controller\Validation;
//FOSRestBundle
use FOS\RestBundle\View\View;
class ClientsController extends Controller
{
//Query all clients
public function getClientsAction(Request $request)
{
$request_type = $request->headers->get('X-Requested-With');
if($request_type != 'XMLHttpRequest') {
return $this->render('HvHDashboardBundle:Dashboard:dashboard.html.twig' );
}
//get any query strings
$query_strings = $request->query->all();
$definition = $this->get("service.handler")->definition_handler(__CLASS__, __FUNCTION__);
//once data has been prepared
return $this->get('fos_rest.view_handler')->handle($view);
}
}
I think the reason the controller isn't getting a container is because you are trying to instantiate and interact with it directly rather than simulating requests using the client (See the section on Functional Tests in the Testing section of the Symfony2 book).
You need something more like this (not sure if the route is correct):
public function testGetClientsAction()
{
$client = static::createClient();
$client->request(
'GET', '/clients/123456',
array(), /* request params */
array(), /* files */
array('X-Requested-With' => "XMLHttpRequest"),
);
$this->assertEquals(200, $client->getResponse()->getStatusCode());
}
Note also, the request() method returns a crawler instance which provides helper methods to verify the content of the response if required.

symfony2: trying to render a form in the template

I'm trying to render a form that I've just generated from an entity, but Im getting the error below...
<?php
namespace Prueba\FrontendBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Prueba\FrontendBundle\Form\ItemType;
class DefaultController extends Controller
{
/**
* #Route("/hello")
* #Template()
*/
public function indexAction($name)
{
$form = new ItemType();var_dump(get_class($form));
return $this->render('AcmeTaskBundle:Default:new.html.twig', array(
'form' => $form->createView(),
));
}
}
string(35) "Prueba\FrontendBundle\Form\ItemType" Fatal error: Call to
undefined method Prueba\FrontendBundle\Form\ItemType::createView() in
/home/javier/programacion/sf2000/src/Prueba/FrontendBundle/Controller/DefaultController.php
on line 20
Change
$form = new ItemType();
to
$form = $this->createForm(new FormType());
And if you want to attach an empty entity to the form (easier validation and form processing):
$item = new Item();
$form = $this->createForm(new FormType(), $item);

Resources