Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2: Test on ArrayCollection gives "Unreachable field"

In a functional test of a form to add members of an ArrayCollection there is this statement:

$form['client[members][1][fname]'] = 'Benny';

The field name was verified with a DOM inspector.

The console output at this line is:

InvalidArgumentException: Unreachable field "members"

G:\Documents\workspace\sym\vendor\symfony\symfony\src\Symfony\Component\DomCrawler\Form.php:459
G:\Documents\workspace\sym\vendor\symfony\symfony\src\Symfony\Component\DomCrawler\Form.php:496
G:\Documents\workspace\sym\vendor\symfony\symfony\src\Symfony\Component\DomCrawler\Form.php:319
G:\Documents\workspace\sym\src\Mana\ClientBundle\Tests\Controller\ClientControllerTest.php:57

What method should be used to test the addition of an ArrayCollection member?

Edit as requested (n.b., follow redirects is on):

    //link to trigger adding household member form
    $link = $crawler->selectLink('Add household member')->link();
    $crawler = $client->click($link);
    $form = $crawler->selectButton('Add client')->form();
    $form['client[members][1][fname]'] = 'Benny';
    $form['client[members][1][dob]'] = "3/12/1999";
    $crawler = $client->submit($form);
    $this->assertTrue($crawler->filter('html:contains("Client View Form")')->count() > 0);
like image 340
geoB Avatar asked Mar 16 '13 21:03

geoB


3 Answers

I just had the same issue and after a bit of research I found a solution which helped me. A solution to remove a field from a Collection form type This post is not exactly what you were looking for, this one is for removing an element and not adding new ones. But the principle is the same. What I did instead of $form->setValues() ... $form->getPhpValues() that I've created an array, and POSTed that

In the example bellow, the configurations field of the form is a Collection

    $submitButton = $crawler->selectButton(self::BUTTON_ADD_APPLICATION);
    $form = $submitButton->form();
    $values = array(
        'Setup' => array(
            '_token' => $form['Setup[_token]']->getValue(),
            'name'   => 'My New Setup',
            'configurations' => array(
                0 => array(
                    'country' => 'HUN',
                    'value'   => '3',
                ),
                1 => array(
                    'country' => 'GBR',
                    'value'   => '0',
                ),
            ),
        ),
    );

    $client->request($form->getMethod(), $form->getUri(), $values);

Hope it helps! And thanks for sstok for the original solution!

like image 138
jkrnak Avatar answered Nov 14 '22 22:11

jkrnak


This can be done by calling slightly modified code from the submit() method:

// Get the form.
$form = $crawler->filter('button')->form();

// Get the raw values.
$values = $form->getPhpValues();

// Add fields to the raw values.
$values['task']['tag'][0]['name'] = 'foo';
$values['task']['tag'][1]['name'] = 'bar';

// Submit the form with the existing and new values.
$crawler = $this->client->request($form->getMethod(), $form->getUri(), $values,
    $form->getPhpFiles());

// The 2 tags have been added to the collection.
$this->assertEquals(2, $crawler->filter('ul.tags > li')->count());

The array with the news values in this example correspond to a form where you have a fields with these names:

<input type="…" name="FORM_NAME[COLLECTION_NAME][A_NUMBER][FIELD_NAME_1]" />
<input type="…" name="FORM_NAME[COLLECTION_NAME][A_NUMBER][FIELD_NAME_2]" />

With this code, the existing fields (including token) are already present in the form, that means you don't need to add all the fields.

The number (index) of the fields is irrelevant, PHP will merge the arrays and submit the data, Symfony will transform this data in the corresponding fields.

You can also remove an element from a collection:

// Get the values of the form.
$values = $form->getPhpValues();

// Remove the first tag.
unset($values['task']['tags'][0]);

// Submit the data.
$crawler = $client->request($form->getMethod(), $form->getUri(),
    $values, $form->getPhpFiles());

// The tag has been removed.
$this->assertEquals(0, $crawler->filter('ul.tags > li')->count());

Source: http://symfony.com/doc/current/book/testing.html#adding-and-removing-forms-to-a-collection

like image 34
A.L Avatar answered Nov 14 '22 22:11

A.L


If you modify the form with javascript, you cannot test it with the symfony test framework. The reason for this is that the DomCrawler provided by symfony does only fetch the static HTML and parses it, not taking into account any manipulations which would be done by a browser with a graphical user interface (mainly javascript).

If you need to test a javascript-heavy project you need to use some framework which either uses the engine of a browser (e.g. Selenium) or which can interpret the javascript and execute all changes on the DOM (e.g. Zombie.js).

A good framework to do this is Mink, which is a layer between the testing framework and the actual client doing the request and parsing the result. It provides an API to work witha very simple PHP HTML Parser (similar to the DomCrawler used by symfony), Selenium, Zombie.js and some more.

like image 2
Sgoettschkes Avatar answered Nov 14 '22 21:11

Sgoettschkes