9

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);
12
  • Can you var_dump $form please? Commented Mar 16, 2013 at 21:36
  • Need to figure out how to get complete $form in a format that will be useful. Windows console abbreviates such that there is no useful information. var_dump to output buffer does not add anything. Commented Mar 16, 2013 at 21:54
  • Oh right because the output is too large, nevermind. Could you copy/paste your asserts and the code that leads to it? Commented Mar 16, 2013 at 21:59
  • Included in edit above. Did learn that one can capture var_export($form) into the buffer then put in a file - there's the large output. Commented Mar 16, 2013 at 22:11
  • Could you gist the content of your html page ? Commented Mar 17, 2013 at 11:18

4 Answers 4

10

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!

Sign up to request clarification or add additional context in comments.

2 Comments

This looks to be useful. I'm finding the documentation on behat, mink & selenium to be impenetrable. So if I can't do the full-tilt bogey on behavioral testing I'll likely do something like you propose. Thanks.
Made this my accepted answer - I was at least able to make it work for me. While not perfect, it is substantially better than not testing the ArrayCollection at all.
5

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

Comments

2

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.

2 Comments

Thanks. I'm off now to Behat, etc., land.
Sorry about the unchecking of answer - I'm sufficiently obtuse as not to be able to make this work for me. Perhaps when there's better documentation...
0

I had a similar problem and in my case I realized that it was because I was not using the right crawler, I was using the one from a previous page with a slightly different form. So I think this is a good place to give the solution that worked in my case.

By getting a fresh crawler on the right web page it works

    $crawler = $client->getCrawler();
    //processing the form
    // ...

and to avoid mistakes I use the syntax

$crawler = $client->submitForm('Add client', [
            'client[members][1][fname]' => 'Benny',
            'client[members][1][dob]' => "3/12/1999",
        ]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.