"Fossies" - the Fresh Open Source Software Archive

Member "Symfony/vendor/symfony/symfony/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php" (30 Mar 2020, 30696 Bytes) of package /linux/www/Symfony_Standard_Vendors_3.4.39.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 <?php
    2 
    3 /*
    4  * This file is part of the Symfony package.
    5  *
    6  * (c) Fabien Potencier <fabien@symfony.com>
    7  *
    8  * For the full copyright and license information, please view the LICENSE
    9  * file that was distributed with this source code.
   10  */
   11 
   12 namespace Symfony\Component\Form\Tests;
   13 
   14 use Symfony\Component\Form\FormError;
   15 use Symfony\Component\Security\Csrf\CsrfToken;
   16 
   17 abstract class AbstractDivLayoutTest extends AbstractLayoutTest
   18 {
   19     public function testRow()
   20     {
   21         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType');
   22         $form->addError(new FormError('[trans]Error![/trans]'));
   23         $view = $form->createView();
   24         $html = $this->renderRow($view);
   25 
   26         $this->assertMatchesXpath($html,
   27 '/div
   28     [
   29         ./label[@for="name"]
   30         /following-sibling::ul
   31             [./li[.="[trans]Error![/trans]"]]
   32             [count(./li)=1]
   33         /following-sibling::input[@id="name"]
   34     ]
   35 '
   36         );
   37     }
   38 
   39     public function testRowOverrideVariables()
   40     {
   41         $view = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType')->createView();
   42         $html = $this->renderRow($view, [
   43             'attr' => ['class' => 'my&class'],
   44             'label' => 'foo&bar',
   45             'label_attr' => ['class' => 'my&label&class'],
   46         ]);
   47 
   48         $this->assertMatchesXpath($html,
   49 '/div
   50     [
   51         ./label[@for="name"][@class="my&label&class required"][.="[trans]foo&bar[/trans]"]
   52         /following-sibling::input[@id="name"][@class="my&class"]
   53     ]
   54 '
   55         );
   56     }
   57 
   58     public function testRepeatedRow()
   59     {
   60         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\RepeatedType');
   61         $form->addError(new FormError('[trans]Error![/trans]'));
   62         $view = $form->createView();
   63         $html = $this->renderRow($view);
   64 
   65         // The errors of the form are not rendered by intention!
   66         // In practice, repeated fields cannot have errors as all errors
   67         // on them are mapped to the first child.
   68         // (see RepeatedTypeValidatorExtension)
   69 
   70         $this->assertMatchesXpath($html,
   71 '/div
   72     [
   73         ./label[@for="name_first"]
   74         /following-sibling::input[@id="name_first"]
   75     ]
   76 /following-sibling::div
   77     [
   78         ./label[@for="name_second"]
   79         /following-sibling::input[@id="name_second"]
   80     ]
   81 '
   82         );
   83     }
   84 
   85     public function testButtonRow()
   86     {
   87         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ButtonType');
   88         $view = $form->createView();
   89         $html = $this->renderRow($view);
   90 
   91         $this->assertMatchesXpath($html,
   92 '/div
   93     [
   94         ./button[@type="button"][@name="name"]
   95     ]
   96     [count(//label)=0]
   97 '
   98         );
   99     }
  100 
  101     public function testRest()
  102     {
  103         $view = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  104             ->add('field1', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  105             ->add('field2', 'Symfony\Component\Form\Extension\Core\Type\RepeatedType')
  106             ->add('field3', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  107             ->add('field4', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  108             ->getForm()
  109             ->createView();
  110 
  111         // Render field2 row -> does not implicitly call renderWidget because
  112         // it is a repeated field!
  113         $this->renderRow($view['field2']);
  114 
  115         // Render field3 widget
  116         $this->renderWidget($view['field3']);
  117 
  118         // Rest should only contain field1 and field4
  119         $html = $this->renderRest($view);
  120 
  121         $this->assertMatchesXpath($html,
  122 '/div
  123     [
  124         ./label[@for="name_field1"]
  125         /following-sibling::input[@type="text"][@id="name_field1"]
  126     ]
  127 /following-sibling::div
  128     [
  129         ./label[@for="name_field4"]
  130         /following-sibling::input[@type="text"][@id="name_field4"]
  131     ]
  132     [count(../div)=2]
  133     [count(..//label)=2]
  134     [count(..//input)=3]
  135 /following-sibling::input
  136     [@type="hidden"]
  137     [@id="name__token"]
  138 '
  139         );
  140     }
  141 
  142     public function testRestWithChildrenForms()
  143     {
  144         $child1 = $this->factory->createNamedBuilder('child1', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  145             ->add('field1', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  146             ->add('field2', 'Symfony\Component\Form\Extension\Core\Type\TextType');
  147 
  148         $child2 = $this->factory->createNamedBuilder('child2', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  149             ->add('field1', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  150             ->add('field2', 'Symfony\Component\Form\Extension\Core\Type\TextType');
  151 
  152         $view = $this->factory->createNamedBuilder('parent', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  153             ->add($child1)
  154             ->add($child2)
  155             ->getForm()
  156             ->createView();
  157 
  158         // Render child1.field1 row
  159         $this->renderRow($view['child1']['field1']);
  160 
  161         // Render child2.field2 widget (remember that widget don't render label)
  162         $this->renderWidget($view['child2']['field2']);
  163 
  164         // Rest should only contain child1.field2 and child2.field1
  165         $html = $this->renderRest($view);
  166 
  167         $this->assertMatchesXpath($html,
  168 '/div
  169     [
  170         ./label[not(@for)]
  171         /following-sibling::div[@id="parent_child1"]
  172             [
  173                 ./div
  174                     [
  175                         ./label[@for="parent_child1_field2"]
  176                         /following-sibling::input[@id="parent_child1_field2"]
  177                     ]
  178             ]
  179     ]
  180 
  181 /following-sibling::div
  182     [
  183         ./label[not(@for)]
  184         /following-sibling::div[@id="parent_child2"]
  185             [
  186                 ./div
  187                     [
  188                         ./label[@for="parent_child2_field1"]
  189                         /following-sibling::input[@id="parent_child2_field1"]
  190                     ]
  191             ]
  192     ]
  193     [count(//label)=4]
  194     [count(//input[@type="text"])=2]
  195 /following-sibling::input[@type="hidden"][@id="parent__token"]
  196 '
  197         );
  198     }
  199 
  200     public function testRestAndRepeatedWithRow()
  201     {
  202         $view = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  203             ->add('first', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  204             ->add('password', 'Symfony\Component\Form\Extension\Core\Type\RepeatedType')
  205             ->getForm()
  206             ->createView();
  207 
  208         $this->renderRow($view['password']);
  209 
  210         $html = $this->renderRest($view);
  211 
  212         $this->assertMatchesXpath($html,
  213 '/div
  214     [
  215         ./label[@for="name_first"]
  216         /following-sibling::input[@type="text"][@id="name_first"]
  217     ]
  218     [count(.//input)=1]
  219 /following-sibling::input
  220     [@type="hidden"]
  221     [@id="name__token"]
  222 '
  223         );
  224     }
  225 
  226     public function testRestAndRepeatedWithRowPerChild()
  227     {
  228         $view = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  229             ->add('first', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  230             ->add('password', 'Symfony\Component\Form\Extension\Core\Type\RepeatedType')
  231             ->getForm()
  232             ->createView();
  233 
  234         $this->renderRow($view['password']['first']);
  235         $this->renderRow($view['password']['second']);
  236 
  237         $html = $this->renderRest($view);
  238 
  239         $this->assertMatchesXpath($html,
  240 '/div
  241     [
  242         ./label[@for="name_first"]
  243         /following-sibling::input[@type="text"][@id="name_first"]
  244     ]
  245     [count(.//input)=1]
  246     [count(.//label)=1]
  247 /following-sibling::input
  248     [@type="hidden"]
  249     [@id="name__token"]
  250 '
  251         );
  252     }
  253 
  254     public function testRestAndRepeatedWithWidgetPerChild()
  255     {
  256         $view = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  257             ->add('first', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  258             ->add('password', 'Symfony\Component\Form\Extension\Core\Type\RepeatedType')
  259             ->getForm()
  260             ->createView();
  261 
  262         // The password form is considered as rendered as all its children
  263         // are rendered
  264         $this->renderWidget($view['password']['first']);
  265         $this->renderWidget($view['password']['second']);
  266 
  267         $html = $this->renderRest($view);
  268 
  269         $this->assertMatchesXpath($html,
  270 '/div
  271     [
  272         ./label[@for="name_first"]
  273         /following-sibling::input[@type="text"][@id="name_first"]
  274     ]
  275     [count(//input)=2]
  276     [count(//label)=1]
  277 /following-sibling::input
  278     [@type="hidden"]
  279     [@id="name__token"]
  280 '
  281         );
  282     }
  283 
  284     public function testCollection()
  285     {
  286         $form = $this->factory->createNamed('names', 'Symfony\Component\Form\Extension\Core\Type\CollectionType', ['a', 'b'], [
  287             'entry_type' => 'Symfony\Component\Form\Extension\Core\Type\TextType',
  288         ]);
  289 
  290         $this->assertWidgetMatchesXpath($form->createView(), [],
  291 '/div
  292     [
  293         ./div[./input[@type="text"][@value="a"]]
  294         /following-sibling::div[./input[@type="text"][@value="b"]]
  295     ]
  296     [count(./div[./input])=2]
  297 '
  298         );
  299     }
  300 
  301     // https://github.com/symfony/symfony/issues/5038
  302     public function testCollectionWithAlternatingRowTypes()
  303     {
  304         $data = [
  305             ['title' => 'a'],
  306             ['title' => 'b'],
  307         ];
  308         $form = $this->factory->createNamed('names', 'Symfony\Component\Form\Extension\Core\Type\CollectionType', $data, [
  309             'entry_type' => 'Symfony\Component\Form\Tests\Fixtures\AlternatingRowType',
  310         ]);
  311 
  312         $this->assertWidgetMatchesXpath($form->createView(), [],
  313 '/div
  314     [
  315         ./div[./div/div/input[@type="text"][@value="a"]]
  316         /following-sibling::div[./div/div/textarea[.="b"]]
  317     ]
  318     [count(./div[./div/div/input])=1]
  319     [count(./div[./div/div/textarea])=1]
  320 '
  321         );
  322     }
  323 
  324     public function testEmptyCollection()
  325     {
  326         $form = $this->factory->createNamed('names', 'Symfony\Component\Form\Extension\Core\Type\CollectionType', [], [
  327             'entry_type' => 'Symfony\Component\Form\Extension\Core\Type\TextType',
  328         ]);
  329 
  330         $this->assertWidgetMatchesXpath($form->createView(), [],
  331 '/div
  332     [./input[@type="hidden"][@id="names__token"]]
  333     [count(./div)=0]
  334 '
  335         );
  336     }
  337 
  338     public function testCollectionRow()
  339     {
  340         $collection = $this->factory->createNamedBuilder(
  341             'collection',
  342             'Symfony\Component\Form\Extension\Core\Type\CollectionType',
  343             ['a', 'b'],
  344             ['entry_type' => 'Symfony\Component\Form\Extension\Core\Type\TextType']
  345         );
  346 
  347         $form = $this->factory->createNamedBuilder('form', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  348             ->add($collection)
  349             ->getForm();
  350 
  351         $this->assertWidgetMatchesXpath($form->createView(), [],
  352 '/div
  353     [
  354         ./div
  355             [
  356                 ./label[not(@for)]
  357                 /following-sibling::div
  358                     [
  359                         ./div
  360                             [
  361                                 ./label[@for="form_collection_0"]
  362                                 /following-sibling::input[@type="text"][@value="a"]
  363                             ]
  364                         /following-sibling::div
  365                             [
  366                                 ./label[@for="form_collection_1"]
  367                                 /following-sibling::input[@type="text"][@value="b"]
  368                             ]
  369                     ]
  370             ]
  371         /following-sibling::input[@type="hidden"][@id="form__token"]
  372     ]
  373     [count(.//input)=3]
  374 '
  375         );
  376     }
  377 
  378     public function testForm()
  379     {
  380         $form = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  381             ->setMethod('PUT')
  382             ->setAction('http://example.com')
  383             ->add('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  384             ->add('lastName', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  385             ->getForm();
  386 
  387         // include ampersands everywhere to validate escaping
  388         $html = $this->renderForm($form->createView(), [
  389             'id' => 'my&id',
  390             'attr' => ['class' => 'my&class'],
  391         ]);
  392 
  393         $this->assertMatchesXpath($html,
  394 '/form
  395     [
  396         ./input[@type="hidden"][@name="_method"][@value="PUT"]
  397         /following-sibling::div
  398             [
  399                 ./div
  400                     [
  401                         ./label[@for="name_firstName"]
  402                         /following-sibling::input[@type="text"][@id="name_firstName"]
  403                     ]
  404                 /following-sibling::div
  405                     [
  406                         ./label[@for="name_lastName"]
  407                         /following-sibling::input[@type="text"][@id="name_lastName"]
  408                     ]
  409                 /following-sibling::input[@type="hidden"][@id="name__token"]
  410             ]
  411             [count(.//input)=3]
  412             [@id="my&id"]
  413             [@class="my&class"]
  414     ]
  415     [@method="post"]
  416     [@action="http://example.com"]
  417     [@class="my&class"]
  418 '
  419         );
  420     }
  421 
  422     public function testFormWidget()
  423     {
  424         $form = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  425             ->add('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  426             ->add('lastName', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  427             ->getForm();
  428 
  429         $this->assertWidgetMatchesXpath($form->createView(), [],
  430 '/div
  431     [
  432         ./div
  433             [
  434                 ./label[@for="name_firstName"]
  435                 /following-sibling::input[@type="text"][@id="name_firstName"]
  436             ]
  437         /following-sibling::div
  438             [
  439                 ./label[@for="name_lastName"]
  440                 /following-sibling::input[@type="text"][@id="name_lastName"]
  441             ]
  442         /following-sibling::input[@type="hidden"][@id="name__token"]
  443     ]
  444     [count(.//input)=3]
  445 '
  446         );
  447     }
  448 
  449     // https://github.com/symfony/symfony/issues/2308
  450     public function testNestedFormError()
  451     {
  452         $form = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  453             ->add($this->factory
  454                 ->createNamedBuilder('child', 'Symfony\Component\Form\Extension\Core\Type\FormType', null, ['error_bubbling' => false])
  455                 ->add('grandChild', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  456             )
  457             ->getForm();
  458 
  459         $form->get('child')->addError(new FormError('[trans]Error![/trans]'));
  460 
  461         $this->assertWidgetMatchesXpath($form->createView(), [],
  462 '/div
  463     [
  464         ./div/label
  465         /following-sibling::ul[./li[.="[trans]Error![/trans]"]]
  466     ]
  467     [count(.//li[.="[trans]Error![/trans]"])=1]
  468 '
  469         );
  470     }
  471 
  472     public function testCsrf()
  473     {
  474         $this->csrfTokenManager->expects($this->any())
  475             ->method('getToken')
  476             ->willReturn(new CsrfToken('token_id', 'foo&bar'));
  477 
  478         $form = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  479             ->add($this->factory
  480                 // No CSRF protection on nested forms
  481                 ->createNamedBuilder('child', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  482                 ->add($this->factory->createNamedBuilder('grandchild', 'Symfony\Component\Form\Extension\Core\Type\TextType'))
  483             )
  484             ->getForm();
  485 
  486         $this->assertWidgetMatchesXpath($form->createView(), [],
  487 '/div
  488     [
  489         ./div
  490         /following-sibling::input[@type="hidden"][@id="name__token"][@value="foo&bar"]
  491     ]
  492     [count(.//input[@type="hidden"])=1]
  493 '
  494         );
  495     }
  496 
  497     public function testRepeated()
  498     {
  499         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\RepeatedType', 'foobar', [
  500             'type' => 'Symfony\Component\Form\Extension\Core\Type\TextType',
  501         ]);
  502 
  503         $this->assertWidgetMatchesXpath($form->createView(), [],
  504 '/div
  505     [
  506         ./div
  507             [
  508                 ./label[@for="name_first"]
  509                 /following-sibling::input[@type="text"][@id="name_first"]
  510             ]
  511         /following-sibling::div
  512             [
  513                 ./label[@for="name_second"]
  514                 /following-sibling::input[@type="text"][@id="name_second"]
  515             ]
  516         /following-sibling::input[@type="hidden"][@id="name__token"]
  517     ]
  518     [count(.//input)=3]
  519 '
  520         );
  521     }
  522 
  523     public function testRepeatedWithCustomOptions()
  524     {
  525         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\RepeatedType', null, [
  526             // the global required value cannot be overridden
  527             'first_options' => ['label' => 'Test', 'required' => false],
  528             'second_options' => ['label' => 'Test2'],
  529         ]);
  530 
  531         $this->assertWidgetMatchesXpath($form->createView(), [],
  532 '/div
  533     [
  534         ./div
  535             [
  536                 ./label[@for="name_first"][.="[trans]Test[/trans]"]
  537                 /following-sibling::input[@type="text"][@id="name_first"][@required="required"]
  538             ]
  539         /following-sibling::div
  540             [
  541                 ./label[@for="name_second"][.="[trans]Test2[/trans]"]
  542                 /following-sibling::input[@type="text"][@id="name_second"][@required="required"]
  543             ]
  544         /following-sibling::input[@type="hidden"][@id="name__token"]
  545     ]
  546     [count(.//input)=3]
  547 '
  548         );
  549     }
  550 
  551     public function testSearchInputName()
  552     {
  553         $form = $this->factory->createNamedBuilder('full', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  554             ->add('name', 'Symfony\Component\Form\Extension\Core\Type\SearchType')
  555             ->getForm();
  556 
  557         $this->assertWidgetMatchesXpath($form->createView(), [],
  558 '/div
  559     [
  560         ./div
  561             [
  562                 ./label[@for="full_name"]
  563                 /following-sibling::input[@type="search"][@id="full_name"][@name="full[name]"]
  564             ]
  565         /following-sibling::input[@type="hidden"][@id="full__token"]
  566     ]
  567     [count(//input)=2]
  568 '
  569         );
  570     }
  571 
  572     public function testLabelHasNoId()
  573     {
  574         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType');
  575         $html = $this->renderRow($form->createView());
  576 
  577         $this->assertMatchesXpath($html,
  578 '/div
  579     [
  580         ./label[@for="name"][not(@id)]
  581         /following-sibling::input[@id="name"]
  582     ]
  583 '
  584         );
  585     }
  586 
  587     public function testLabelIsNotRenderedWhenSetToFalse()
  588     {
  589         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [
  590             'label' => false,
  591         ]);
  592         $html = $this->renderRow($form->createView());
  593 
  594         $this->assertMatchesXpath($html,
  595 '/div
  596     [
  597         ./input[@id="name"]
  598     ]
  599     [count(//label)=0]
  600 '
  601         );
  602     }
  603 
  604     /**
  605      * @dataProvider themeBlockInheritanceProvider
  606      */
  607     public function testThemeBlockInheritance($theme)
  608     {
  609         $view = $this->factory
  610             ->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\EmailType')
  611             ->createView()
  612         ;
  613 
  614         $this->setTheme($view, $theme);
  615 
  616         $this->assertMatchesXpath(
  617             $this->renderWidget($view),
  618             '/input[@type="email"][@rel="theme"]'
  619         );
  620     }
  621 
  622     /**
  623      * @dataProvider themeInheritanceProvider
  624      */
  625     public function testThemeInheritance($parentTheme, $childTheme)
  626     {
  627         $child = $this->factory->createNamedBuilder('child', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  628             ->add('field', 'Symfony\Component\Form\Extension\Core\Type\TextType');
  629 
  630         $view = $this->factory->createNamedBuilder('parent', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  631             ->add('field', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  632             ->add($child)
  633             ->getForm()
  634             ->createView()
  635         ;
  636 
  637         $this->setTheme($view, $parentTheme);
  638         $this->setTheme($view['child'], $childTheme);
  639 
  640         $this->assertWidgetMatchesXpath($view, [],
  641 '/div
  642     [
  643         ./div
  644             [
  645                 ./label[.="parent"]
  646                 /following-sibling::input[@type="text"]
  647             ]
  648         /following-sibling::div
  649             [
  650                 ./label[.="child"]
  651                 /following-sibling::div
  652                     [
  653                         ./div
  654                             [
  655                                 ./label[.="child"]
  656                                 /following-sibling::input[@type="text"]
  657                             ]
  658                     ]
  659             ]
  660         /following-sibling::input[@type="hidden"]
  661     ]
  662 '
  663         );
  664     }
  665 
  666     /**
  667      * The block "_name_child_label" should be overridden in the theme of the
  668      * implemented driver.
  669      */
  670     public function testCollectionRowWithCustomBlock()
  671     {
  672         $collection = ['one', 'two', 'three'];
  673         $form = $this->factory->createNamedBuilder('names', 'Symfony\Component\Form\Extension\Core\Type\CollectionType', $collection)
  674             ->getForm();
  675 
  676         $this->assertWidgetMatchesXpath($form->createView(), [],
  677 '/div
  678     [
  679         ./div[./label[.="Custom label: [trans]0[/trans]"]]
  680         /following-sibling::div[./label[.="Custom label: [trans]1[/trans]"]]
  681         /following-sibling::div[./label[.="Custom label: [trans]2[/trans]"]]
  682     ]
  683 '
  684         );
  685     }
  686 
  687     /**
  688      * The block "_name_c_entry_label" should be overridden in the theme of the
  689      * implemented driver.
  690      */
  691     public function testChoiceRowWithCustomBlock()
  692     {
  693         $form = $this->factory->createNamedBuilder('name_c', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', 'a', [
  694                 'choices' => ['ChoiceA' => 'a', 'ChoiceB' => 'b'],
  695                 'expanded' => true,
  696             ])
  697             ->getForm();
  698 
  699         $this->assertWidgetMatchesXpath($form->createView(), [],
  700 '/div
  701     [
  702         ./label[.="Custom name label: [trans]ChoiceA[/trans]"]
  703         /following-sibling::label[.="Custom name label: [trans]ChoiceB[/trans]"]
  704     ]
  705 '
  706         );
  707     }
  708 
  709     public function testSingleChoiceExpandedWithLabelsAsFalse()
  710     {
  711         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', [
  712             'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b'],
  713             'choice_label' => false,
  714             'multiple' => false,
  715             'expanded' => true,
  716         ]);
  717 
  718         $this->assertWidgetMatchesXpath($form->createView(), [],
  719             '/div
  720     [
  721         ./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
  722         /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
  723         /following-sibling::input[@type="hidden"][@id="name__token"]
  724     ]
  725     [count(./input)=3]
  726     [count(./label)=1]
  727 '
  728         );
  729     }
  730 
  731     public function testSingleChoiceExpandedWithLabelsSetByCallable()
  732     {
  733         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', [
  734             'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'],
  735             'choice_label' => function ($choice, $label, $value) {
  736                 if ('&b' === $choice) {
  737                     return false;
  738                 }
  739 
  740                 return 'label.'.$value;
  741             },
  742             'multiple' => false,
  743             'expanded' => true,
  744         ]);
  745 
  746         $this->assertWidgetMatchesXpath($form->createView(), [],
  747             '/div
  748     [
  749         ./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
  750         /following-sibling::label[@for="name_0"][.="[trans]label.&a[/trans]"]
  751         /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
  752         /following-sibling::input[@type="radio"][@name="name"][@id="name_2"][@value="&c"][not(@checked)]
  753         /following-sibling::label[@for="name_2"][.="[trans]label.&c[/trans]"]
  754         /following-sibling::input[@type="hidden"][@id="name__token"]
  755     ]
  756     [count(./input)=4]
  757     [count(./label)=3]
  758 '
  759         );
  760     }
  761 
  762     public function testSingleChoiceExpandedWithLabelsSetFalseByCallable()
  763     {
  764         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', [
  765             'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b'],
  766             'choice_label' => function () {
  767                 return false;
  768             },
  769             'multiple' => false,
  770             'expanded' => true,
  771         ]);
  772 
  773         $this->assertWidgetMatchesXpath($form->createView(), [],
  774             '/div
  775     [
  776         ./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
  777         /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
  778         /following-sibling::input[@type="hidden"][@id="name__token"]
  779     ]
  780     [count(./input)=3]
  781     [count(./label)=1]
  782 '
  783         );
  784     }
  785 
  786     public function testMultipleChoiceExpandedWithLabelsAsFalse()
  787     {
  788         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', ['&a'], [
  789             'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b'],
  790             'choice_label' => false,
  791             'multiple' => true,
  792             'expanded' => true,
  793         ]);
  794 
  795         $this->assertWidgetMatchesXpath($form->createView(), [],
  796 '/div
  797     [
  798         ./input[@type="checkbox"][@name="name[]"][@id="name_0"][@value="&a"][@checked]
  799         /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_1"][@value="&b"][not(@checked)]
  800         /following-sibling::input[@type="hidden"][@id="name__token"]
  801     ]
  802     [count(./input)=3]
  803     [count(./label)=1]
  804 '
  805         );
  806     }
  807 
  808     public function testMultipleChoiceExpandedWithLabelsSetByCallable()
  809     {
  810         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', ['&a'], [
  811             'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c'],
  812             'choice_label' => function ($choice, $label, $value) {
  813                 if ('&b' === $choice) {
  814                     return false;
  815                 }
  816 
  817                 return 'label.'.$value;
  818             },
  819             'multiple' => true,
  820             'expanded' => true,
  821         ]);
  822 
  823         $this->assertWidgetMatchesXpath($form->createView(), [],
  824 '/div
  825     [
  826         ./input[@type="checkbox"][@name="name[]"][@id="name_0"][@value="&a"][@checked]
  827         /following-sibling::label[@for="name_0"][.="[trans]label.&a[/trans]"]
  828         /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_1"][@value="&b"][not(@checked)]
  829         /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_2"][@value="&c"][not(@checked)]
  830         /following-sibling::label[@for="name_2"][.="[trans]label.&c[/trans]"]
  831         /following-sibling::input[@type="hidden"][@id="name__token"]
  832     ]
  833     [count(./input)=4]
  834     [count(./label)=3]
  835 '
  836         );
  837     }
  838 
  839     public function testMultipleChoiceExpandedWithLabelsSetFalseByCallable()
  840     {
  841         $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', ['&a'], [
  842             'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b'],
  843             'choice_label' => function () {
  844                 return false;
  845             },
  846             'multiple' => true,
  847             'expanded' => true,
  848         ]);
  849 
  850         $this->assertWidgetMatchesXpath($form->createView(), [],
  851 '/div
  852     [
  853         ./input[@type="checkbox"][@name="name[]"][@id="name_0"][@value="&a"][@checked]
  854         /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_1"][@value="&b"][not(@checked)]
  855         /following-sibling::input[@type="hidden"][@id="name__token"]
  856     ]
  857     [count(./input)=3]
  858     [count(./label)=1]
  859 '
  860         );
  861     }
  862 
  863     public function testFormEndWithRest()
  864     {
  865         $view = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  866             ->add('field1', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  867             ->add('field2', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  868             ->getForm()
  869             ->createView();
  870 
  871         $this->renderWidget($view['field1']);
  872 
  873         // Rest should only contain field2
  874         $html = $this->renderEnd($view);
  875 
  876         // Insert the start tag, the end tag should be rendered by the helper
  877         $this->assertMatchesXpath('<form>'.$html,
  878 '/form
  879     [
  880         ./div
  881             [
  882                 ./label[@for="name_field2"]
  883                 /following-sibling::input[@type="text"][@id="name_field2"]
  884             ]
  885         /following-sibling::input
  886             [@type="hidden"]
  887             [@id="name__token"]
  888     ]
  889 '
  890         );
  891     }
  892 
  893     public function testFormEndWithoutRest()
  894     {
  895         $view = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
  896             ->add('field1', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  897             ->add('field2', 'Symfony\Component\Form\Extension\Core\Type\TextType')
  898             ->getForm()
  899             ->createView();
  900 
  901         $this->renderWidget($view['field1']);
  902 
  903         // Rest should only contain field2, but isn't rendered
  904         $html = $this->renderEnd($view, ['render_rest' => false]);
  905 
  906         $this->assertEquals('</form>', $html);
  907     }
  908 
  909     public function testWidgetContainerAttributes()
  910     {
  911         $form = $this->factory->createNamed('form', 'Symfony\Component\Form\Extension\Core\Type\FormType', null, [
  912             'attr' => ['class' => 'foobar', 'data-foo' => 'bar'],
  913         ]);
  914 
  915         $form->add('text', 'Symfony\Component\Form\Extension\Core\Type\TextType');
  916 
  917         $html = $this->renderWidget($form->createView());
  918 
  919         // compare plain HTML to check the whitespace
  920         $this->assertStringContainsString('<div id="form" class="foobar" data-foo="bar">', $html);
  921     }
  922 
  923     public function testWidgetContainerAttributeNameRepeatedIfTrue()
  924     {
  925         $form = $this->factory->createNamed('form', 'Symfony\Component\Form\Extension\Core\Type\FormType', null, [
  926             'attr' => ['foo' => true],
  927         ]);
  928 
  929         $html = $this->renderWidget($form->createView());
  930 
  931         // foo="foo"
  932         $this->assertStringContainsString('<div id="form" foo="foo">', $html);
  933     }
  934 }