4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Form\Tests
;
14 use Symfony\Component\Form\FormError
;
15 use Symfony\Component\Form\FormView
;
16 use Symfony\Component\Form\Extension\Csrf\CsrfExtension
;
18 abstract class AbstractLayoutTest
extends \Symfony\Component\Form\Test\FormIntegrationTestCase
20 protected $csrfProvider;
22 protected function setUp()
24 if (!extension_loaded('intl')) {
25 $this->markTestSkipped('The "intl" extension is not available');
28 \Locale
::setDefault('en');
30 $this->csrfProvider
= $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
35 protected function getExtensions()
38 new CsrfExtension($this->csrfProvider
),
42 protected function tearDown()
44 $this->csrfProvider
= null;
49 protected function assertXpathNodeValue(\DomElement
$element, $expression, $nodeValue)
51 $xpath = new \
DOMXPath($element->ownerDocument
);
52 $nodeList = $xpath->evaluate($expression);
53 $this->assertEquals(1, $nodeList->length
);
54 $this->assertEquals($nodeValue, $nodeList->item(0)->nodeValue
);
57 protected function assertMatchesXpath($html, $expression, $count = 1)
59 $dom = new \
DomDocument('UTF-8');
61 // Wrap in <root> node so we can load HTML with multiple tags at
63 $dom->loadXml('<root>'.$html.'</root>');
64 } catch (\Exception
$e) {
66 "Failed loading HTML:\n\n%s\n\nError: %s",
71 $xpath = new \
DOMXPath($dom);
72 $nodeList = $xpath->evaluate('/root'.$expression);
74 if ($nodeList->length
!= $count) {
75 $dom->formatOutput
= true;
77 "Failed asserting that \n\n%s\n\nmatches exactly %s. Matches %s in \n\n%s",
79 $count == 1 ? 'once' : $count.' times',
80 $nodeList->length
== 1 ? 'once' : $nodeList->length
.' times',
81 // strip away <root> and </root>
82 substr($dom->saveHTML(), 6, -8)
87 protected function assertWidgetMatchesXpath(FormView
$view, array $vars, $xpath)
89 // include ampersands everywhere to validate escaping
90 $html = $this->renderWidget($view, array_merge(array(
92 'attr' => array('class' => 'my&class'),
95 $xpath = trim($xpath).'
99 $this->assertMatchesXpath($html, $xpath);
102 abstract protected function renderForm(FormView
$view, array $vars = array());
104 abstract protected function renderEnctype(FormView
$view);
106 abstract protected function renderLabel(FormView
$view, $label = null, array $vars = array());
108 abstract protected function renderErrors(FormView
$view);
110 abstract protected function renderWidget(FormView
$view, array $vars = array());
112 abstract protected function renderRow(FormView
$view, array $vars = array());
114 abstract protected function renderRest(FormView
$view, array $vars = array());
116 abstract protected function renderStart(FormView
$view, array $vars = array());
118 abstract protected function renderEnd(FormView
$view, array $vars = array());
120 abstract protected function setTheme(FormView
$view, array $themes);
122 public function testEnctype()
124 $form = $this->factory
->createNamedBuilder('name', 'form')
125 ->add('file', 'file')
128 $this->assertEquals('enctype="multipart/form-data"', $this->renderEnctype($form->createView()));
131 public function testNoEnctype()
133 $form = $this->factory
->createNamedBuilder('name', 'form')
134 ->add('text', 'text')
137 $this->assertEquals('', $this->renderEnctype($form->createView()));
140 public function testLabel()
142 $form = $this->factory
->createNamed('name', 'text');
143 $view = $form->createView();
144 $this->renderWidget($view, array('label' => 'foo'));
145 $html = $this->renderLabel($view);
147 $this->assertMatchesXpath($html,
150 [.="[trans]Name[/trans]"]
155 public function testLabelOnForm()
157 $form = $this->factory
->createNamed('name', 'date');
158 $view = $form->createView();
159 $this->renderWidget($view, array('label' => 'foo'));
160 $html = $this->renderLabel($view);
162 $this->assertMatchesXpath($html,
165 [.="[trans]Name[/trans]"]
170 public function testLabelWithCustomTextPassedAsOption()
172 $form = $this->factory
->createNamed('name', 'text', null, array(
173 'label' => 'Custom label',
175 $html = $this->renderLabel($form->createView());
177 $this->assertMatchesXpath($html,
180 [.="[trans]Custom label[/trans]"]
185 public function testLabelWithCustomTextPassedDirectly()
187 $form = $this->factory
->createNamed('name', 'text');
188 $html = $this->renderLabel($form->createView(), 'Custom label');
190 $this->assertMatchesXpath($html,
193 [.="[trans]Custom label[/trans]"]
198 public function testLabelWithCustomTextPassedAsOptionAndDirectly()
200 $form = $this->factory
->createNamed('name', 'text', null, array(
201 'label' => 'Custom label',
203 $html = $this->renderLabel($form->createView(), 'Overridden label');
205 $this->assertMatchesXpath($html,
208 [.="[trans]Overridden label[/trans]"]
213 public function testLabelDoesNotRenderFieldAttributes()
215 $form = $this->factory
->createNamed('name', 'text');
216 $html = $this->renderLabel($form->createView(), null, array(
218 'class' => 'my&class'
222 $this->assertMatchesXpath($html,
230 public function testLabelWithCustomAttributesPassedDirectly()
232 $form = $this->factory
->createNamed('name', 'text');
233 $html = $this->renderLabel($form->createView(), null, array(
234 'label_attr' => array(
235 'class' => 'my&class'
239 $this->assertMatchesXpath($html,
242 [@class="my&class required"]
247 public function testLabelWithCustomTextAndCustomAttributesPassedDirectly()
249 $form = $this->factory
->createNamed('name', 'text');
250 $html = $this->renderLabel($form->createView(), 'Custom label', array(
251 'label_attr' => array(
252 'class' => 'my&class'
256 $this->assertMatchesXpath($html,
259 [@class="my&class required"]
260 [.="[trans]Custom label[/trans]"]
265 // https://github.com/symfony/symfony/issues/5029
266 public function testLabelWithCustomTextAsOptionAndCustomAttributesPassedDirectly()
268 $form = $this->factory
->createNamed('name', 'text', null, array(
269 'label' => 'Custom label',
271 $html = $this->renderLabel($form->createView(), null, array(
272 'label_attr' => array(
273 'class' => 'my&class'
277 $this->assertMatchesXpath($html,
280 [@class="my&class required"]
281 [.="[trans]Custom label[/trans]"]
286 public function testErrors()
288 $form = $this->factory
->createNamed('name', 'text');
289 $form->addError(new FormError('[trans]Error 1[/trans]'));
290 $form->addError(new FormError('[trans]Error 2[/trans]'));
291 $view = $form->createView();
292 $html = $this->renderErrors($view);
294 $this->assertMatchesXpath($html,
297 ./li[.="[trans]Error 1[/trans]"]
298 /following-sibling::li[.="[trans]Error 2[/trans]"]
305 public function testWidgetById()
307 $form = $this->factory
->createNamed('text_id', 'text');
308 $html = $this->renderWidget($form->createView());
310 $this->assertMatchesXpath($html,
322 public function testCheckedCheckbox()
324 $form = $this->factory
->createNamed('name', 'checkbox', true);
326 $this->assertWidgetMatchesXpath($form->createView(), array(),
336 public function testUncheckedCheckbox()
338 $form = $this->factory
->createNamed('name', 'checkbox', false);
340 $this->assertWidgetMatchesXpath($form->createView(), array(),
349 public function testCheckboxWithValue()
351 $form = $this->factory
->createNamed('name', 'checkbox', false, array(
352 'value' => 'foo&bar',
355 $this->assertWidgetMatchesXpath($form->createView(), array(),
364 public function testSingleChoice()
366 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
367 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
372 $this->assertWidgetMatchesXpath($form->createView(), array(),
375 [@required="required"]
377 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
378 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
385 public function testSingleChoiceWithPreferred()
387 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
388 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
389 'preferred_choices' => array('&b'),
394 $this->assertWidgetMatchesXpath($form->createView(), array('separator' => '-- sep --'),
397 [@required="required"]
399 ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
400 /following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
401 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
408 public function testSingleChoiceWithPreferredAndNoSeparator()
410 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
411 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
412 'preferred_choices' => array('&b'),
417 $this->assertWidgetMatchesXpath($form->createView(), array('separator' => null),
420 [@required="required"]
422 ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
423 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
430 public function testSingleChoiceWithPreferredAndBlankSeparator()
432 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
433 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
434 'preferred_choices' => array('&b'),
439 $this->assertWidgetMatchesXpath($form->createView(), array('separator' => ''),
442 [@required="required"]
444 ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
445 /following-sibling::option[@disabled="disabled"][not(@selected)][.=""]
446 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
453 public function testChoiceWithOnlyPreferred()
455 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
456 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
457 'preferred_choices' => array('&a', '&b'),
462 $this->assertWidgetMatchesXpath($form->createView(), array(),
469 public function testSingleChoiceNonRequired()
471 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
472 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
478 $this->assertWidgetMatchesXpath($form->createView(), array(),
483 ./option[@value=""][.="[trans][/trans]"]
484 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
485 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
492 public function testSingleChoiceNonRequiredNoneSelected()
494 $form = $this->factory
->createNamed('name', 'choice', null, array(
495 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
501 $this->assertWidgetMatchesXpath($form->createView(), array(),
506 ./option[@value=""][.="[trans][/trans]"]
507 /following-sibling::option[@value="&a"][not(@selected)][.="[trans]Choice&A[/trans]"]
508 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
515 public function testSingleChoiceWithNonRequiredEmptyValue()
517 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
518 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
522 'empty_value' => 'Select&Anything&Not&Me',
525 $this->assertWidgetMatchesXpath($form->createView(), array(),
530 ./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Anything&Not&Me[/trans]"]
531 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
532 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
539 public function testSingleChoiceRequiredWithEmptyValue()
541 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
542 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
546 'empty_value' => 'Test&Me'
549 $this->assertWidgetMatchesXpath($form->createView(), array(),
552 [@required="required"]
554 ./option[not(@value)][not(@selected)][@disabled][.="[trans]Test&Me[/trans]"]
555 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
556 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
563 public function testSingleChoiceRequiredWithEmptyValueViaView()
565 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
566 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
572 $this->assertWidgetMatchesXpath($form->createView(), array('empty_value' => ''),
575 [@required="required"]
577 ./option[not(@value)][not(@selected)][@disabled][.="[trans][/trans]"]
578 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
579 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
586 public function testSingleChoiceGrouped()
588 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
590 'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
591 'Group&2' => array('&c' => 'Choice&C'),
597 $this->assertWidgetMatchesXpath($form->createView(), array(),
600 [./optgroup[@label="[trans]Group&1[/trans]"]
602 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
603 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
607 [./optgroup[@label="[trans]Group&2[/trans]"]
608 [./option[@value="&c"][not(@selected)][.="[trans]Choice&C[/trans]"]]
611 [count(./optgroup)=2]
616 public function testMultipleChoice()
618 $form = $this->factory
->createNamed('name', 'choice', array('&a'), array(
619 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
624 $this->assertWidgetMatchesXpath($form->createView(), array(),
627 [@multiple="multiple"]
629 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
630 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
637 public function testMultipleChoiceSkipsEmptyValue()
639 $form = $this->factory
->createNamed('name', 'choice', array('&a'), array(
640 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
643 'empty_value' => 'Test&Me'
646 $this->assertWidgetMatchesXpath($form->createView(), array(),
649 [@multiple="multiple"]
651 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
652 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
659 public function testMultipleChoiceNonRequired()
661 $form = $this->factory
->createNamed('name', 'choice', array('&a'), array(
662 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
668 $this->assertWidgetMatchesXpath($form->createView(), array(),
671 [@multiple="multiple"]
673 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
674 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
681 public function testSingleChoiceExpanded()
683 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
684 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
689 $this->assertWidgetMatchesXpath($form->createView(), array(),
692 ./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
693 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
694 /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
695 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
696 /following-sibling::input[@type="hidden"][@id="name__token"]
703 public function testSingleChoiceExpandedWithEmptyValue()
705 $form = $this->factory
->createNamed('name', 'choice', '&a', array(
706 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
709 'empty_value' => 'Test&Me'
712 $this->assertWidgetMatchesXpath($form->createView(), array(),
715 ./input[@type="radio"][@name="name"][@id="name_placeholder"][not(@checked)]
716 /following-sibling::label[@for="name_placeholder"][.="[trans]Test&Me[/trans]"]
717 /following-sibling::input[@type="radio"][@name="name"][@id="name_0"][@checked]
718 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
719 /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
720 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
721 /following-sibling::input[@type="hidden"][@id="name__token"]
728 public function testSingleChoiceExpandedWithBooleanValue()
730 $form = $this->factory
->createNamed('name', 'choice', true, array(
731 'choices' => array('1' => 'Choice&A', '0' => 'Choice&B'),
736 $this->assertWidgetMatchesXpath($form->createView(), array(),
739 ./input[@type="radio"][@name="name"][@id="name_0"][@checked]
740 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
741 /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
742 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
743 /following-sibling::input[@type="hidden"][@id="name__token"]
750 public function testMultipleChoiceExpanded()
752 $form = $this->factory
->createNamed('name', 'choice', array('&a', '&c'), array(
753 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
759 $this->assertWidgetMatchesXpath($form->createView(), array(),
762 ./input[@type="checkbox"][@name="name[]"][@id="name_0"][@checked][not(@required)]
763 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
764 /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_1"][not(@checked)][not(@required)]
765 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
766 /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_2"][@checked][not(@required)]
767 /following-sibling::label[@for="name_2"][.="[trans]Choice&C[/trans]"]
768 /following-sibling::input[@type="hidden"][@id="name__token"]
775 public function testCountry()
777 $form = $this->factory
->createNamed('name', 'country', 'AT');
779 $this->assertWidgetMatchesXpath($form->createView(), array(),
782 [./option[@value="AT"][@selected="selected"][.="[trans]Austria[/trans]"]]
783 [count(./option)>200]
788 public function testCountryWithEmptyValue()
790 $form = $this->factory
->createNamed('name', 'country', 'AT', array(
791 'empty_value' => 'Select&Country',
795 $this->assertWidgetMatchesXpath($form->createView(), array(),
798 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Country[/trans]"]]
799 [./option[@value="AT"][@selected="selected"][.="[trans]Austria[/trans]"]]
800 [count(./option)>201]
805 public function testDateTime()
807 $form = $this->factory
->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
809 'with_seconds' => false,
812 $this->assertWidgetMatchesXpath($form->createView(), array(),
819 [@id="name_date_month"]
820 [./option[@value="2"][@selected="selected"]]
821 /following-sibling::select
822 [@id="name_date_day"]
823 [./option[@value="3"][@selected="selected"]]
824 /following-sibling::select
825 [@id="name_date_year"]
826 [./option[@value="2011"][@selected="selected"]]
828 /following-sibling::div
832 [@id="name_time_hour"]
833 [./option[@value="4"][@selected="selected"]]
834 /following-sibling::select
835 [@id="name_time_minute"]
836 [./option[@value="5"][@selected="selected"]]
844 public function testDateTimeWithEmptyValueGlobal()
846 $form = $this->factory
->createNamed('name', 'datetime', null, array(
848 'empty_value' => 'Change&Me',
852 $this->assertWidgetMatchesXpath($form->createView(), array(),
859 [@id="name_date_month"]
860 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
861 /following-sibling::select
862 [@id="name_date_day"]
863 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
864 /following-sibling::select
865 [@id="name_date_year"]
866 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
868 /following-sibling::div
872 [@id="name_time_hour"]
873 [./option[@value=""][.="[trans]Change&Me[/trans]"]]
874 /following-sibling::select
875 [@id="name_time_minute"]
876 [./option[@value=""][.="[trans]Change&Me[/trans]"]]
884 public function testDateTimeWithEmptyValueOnTime()
886 $data = array('year' => '2011', 'month' => '2', 'day' => '3', 'hour' => '', 'minute' => '');
888 $form = $this->factory
->createNamed('name', 'datetime', $data, array(
890 'empty_value' => array('hour' => 'Change&Me', 'minute' => 'Change&Me'),
894 $this->assertWidgetMatchesXpath($form->createView(), array(),
901 [@id="name_date_month"]
902 [./option[@value="2"][@selected="selected"]]
903 /following-sibling::select
904 [@id="name_date_day"]
905 [./option[@value="3"][@selected="selected"]]
906 /following-sibling::select
907 [@id="name_date_year"]
908 [./option[@value="2011"][@selected="selected"]]
910 /following-sibling::div
914 [@id="name_time_hour"]
915 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
916 /following-sibling::select
917 [@id="name_time_minute"]
918 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
926 public function testDateTimeWithSeconds()
928 $form = $this->factory
->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
930 'with_seconds' => true,
933 $this->assertWidgetMatchesXpath($form->createView(), array(),
940 [@id="name_date_month"]
941 [./option[@value="2"][@selected="selected"]]
942 /following-sibling::select
943 [@id="name_date_day"]
944 [./option[@value="3"][@selected="selected"]]
945 /following-sibling::select
946 [@id="name_date_year"]
947 [./option[@value="2011"][@selected="selected"]]
949 /following-sibling::div
953 [@id="name_time_hour"]
954 [./option[@value="4"][@selected="selected"]]
955 /following-sibling::select
956 [@id="name_time_minute"]
957 [./option[@value="5"][@selected="selected"]]
958 /following-sibling::select
959 [@id="name_time_second"]
960 [./option[@value="6"][@selected="selected"]]
968 public function testDateTimeSingleText()
970 $form = $this->factory
->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
972 'date_widget' => 'single_text',
973 'time_widget' => 'single_text',
976 $this->assertWidgetMatchesXpath($form->createView(), array(),
983 [@value="2011-02-03"]
984 /following-sibling::input
994 public function testDateTimeWithWidgetSingleText()
996 $form = $this->factory
->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
998 'widget' => 'single_text',
999 'model_timezone' => 'UTC',
1000 'view_timezone' => 'UTC',
1003 $this->assertWidgetMatchesXpath($form->createView(), array(),
1007 [@value="2011-02-03T04:05:06Z"]
1012 public function testDateTimeWithWidgetSingleTextIgnoreDateAndTimeWidgets()
1014 $form = $this->factory
->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
1015 'input' => 'string',
1016 'date_widget' => 'choice',
1017 'time_widget' => 'choice',
1018 'widget' => 'single_text',
1019 'model_timezone' => 'UTC',
1020 'view_timezone' => 'UTC',
1023 $this->assertWidgetMatchesXpath($form->createView(), array(),
1027 [@value="2011-02-03T04:05:06Z"]
1032 public function testDateChoice()
1034 $form = $this->factory
->createNamed('name', 'date', '2011-02-03', array(
1035 'input' => 'string',
1036 'widget' => 'choice',
1039 $this->assertWidgetMatchesXpath($form->createView(), array(),
1044 [./option[@value="2"][@selected="selected"]]
1045 /following-sibling::select
1047 [./option[@value="3"][@selected="selected"]]
1048 /following-sibling::select
1050 [./option[@value="2011"][@selected="selected"]]
1057 public function testDateChoiceWithEmptyValueGlobal()
1059 $form = $this->factory
->createNamed('name', 'date', null, array(
1060 'input' => 'string',
1061 'widget' => 'choice',
1062 'empty_value' => 'Change&Me',
1063 'required' => false,
1066 $this->assertWidgetMatchesXpath($form->createView(), array(),
1071 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1072 /following-sibling::select
1074 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1075 /following-sibling::select
1077 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1084 public function testDateChoiceWithEmptyValueOnYear()
1086 $form = $this->factory
->createNamed('name', 'date', null, array(
1087 'input' => 'string',
1088 'widget' => 'choice',
1089 'required' => false,
1090 'empty_value' => array('year' => 'Change&Me'),
1093 $this->assertWidgetMatchesXpath($form->createView(), array(),
1098 [./option[@value="1"]]
1099 /following-sibling::select
1101 [./option[@value="1"]]
1102 /following-sibling::select
1104 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1111 public function testDateText()
1113 $form = $this->factory
->createNamed('name', 'date', '2011-02-03', array(
1114 'input' => 'string',
1118 $this->assertWidgetMatchesXpath($form->createView(), array(),
1125 /following-sibling::input
1129 /following-sibling::input
1139 public function testDateSingleText()
1141 $form = $this->factory
->createNamed('name', 'date', '2011-02-03', array(
1142 'input' => 'string',
1143 'widget' => 'single_text',
1146 $this->assertWidgetMatchesXpath($form->createView(), array(),
1150 [@value="2011-02-03"]
1155 public function testDateErrorBubbling()
1157 $form = $this->factory
->createNamedBuilder('form', 'form')
1158 ->add('date', 'date')
1160 $form->get('date')->addError(new FormError('[trans]Error![/trans]'));
1161 $view = $form->createView();
1163 $this->assertEmpty($this->renderErrors($view));
1164 $this->assertNotEmpty($this->renderErrors($view['date']));
1167 public function testBirthDay()
1169 $form = $this->factory
->createNamed('name', 'birthday', '2000-02-03', array(
1170 'input' => 'string',
1173 $this->assertWidgetMatchesXpath($form->createView(), array(),
1178 [./option[@value="2"][@selected="selected"]]
1179 /following-sibling::select
1181 [./option[@value="3"][@selected="selected"]]
1182 /following-sibling::select
1184 [./option[@value="2000"][@selected="selected"]]
1191 public function testBirthDayWithEmptyValue()
1193 $form = $this->factory
->createNamed('name', 'birthday', '1950-01-01', array(
1194 'input' => 'string',
1195 'empty_value' => '',
1196 'required' => false,
1199 $this->assertWidgetMatchesXpath($form->createView(), array(),
1204 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
1205 [./option[@value="1"][@selected="selected"]]
1206 /following-sibling::select
1208 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
1209 [./option[@value="1"][@selected="selected"]]
1210 /following-sibling::select
1212 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
1213 [./option[@value="1950"][@selected="selected"]]
1220 public function testEmail()
1222 $form = $this->factory
->createNamed('name', 'email', 'foo&bar');
1224 $this->assertWidgetMatchesXpath($form->createView(), array(),
1234 public function testEmailWithMaxLength()
1236 $form = $this->factory
->createNamed('name', 'email', 'foo&bar', array(
1237 'max_length' => 123,
1240 $this->assertWidgetMatchesXpath($form->createView(), array(),
1250 public function testFile()
1252 $form = $this->factory
->createNamed('name', 'file');
1254 $this->assertWidgetMatchesXpath($form->createView(), array(),
1261 public function testHidden()
1263 $form = $this->factory
->createNamed('name', 'hidden', 'foo&bar');
1265 $this->assertWidgetMatchesXpath($form->createView(), array(),
1274 public function testReadOnly()
1276 $form = $this->factory
->createNamed('name', 'text', null, array(
1277 'read_only' => true,
1280 $this->assertWidgetMatchesXpath($form->createView(), array(),
1284 [@readonly="readonly"]
1289 public function testDisabled()
1291 $form = $this->factory
->createNamed('name', 'text', null, array(
1295 $this->assertWidgetMatchesXpath($form->createView(), array(),
1299 [@disabled="disabled"]
1304 public function testInteger()
1306 $form = $this->factory
->createNamed('name', 'integer', 123);
1308 $this->assertWidgetMatchesXpath($form->createView(), array(),
1317 public function testLanguage()
1319 $form = $this->factory
->createNamed('name', 'language', 'de');
1321 $this->assertWidgetMatchesXpath($form->createView(), array(),
1324 [./option[@value="de"][@selected="selected"][.="[trans]German[/trans]"]]
1325 [count(./option)>200]
1330 public function testLocale()
1332 $form = $this->factory
->createNamed('name', 'locale', 'de_AT');
1334 $this->assertWidgetMatchesXpath($form->createView(), array(),
1337 [./option[@value="de_AT"][@selected="selected"][.="[trans]German (Austria)[/trans]"]]
1338 [count(./option)>200]
1343 public function testMoney()
1345 $form = $this->factory
->createNamed('name', 'money', 1234.56, array(
1346 'currency' => 'EUR',
1349 $this->assertWidgetMatchesXpath($form->createView(), array(),
1354 [contains(.., "€")]
1359 public function testNumber()
1361 $form = $this->factory
->createNamed('name', 'number', 1234.56);
1363 $this->assertWidgetMatchesXpath($form->createView(), array(),
1372 public function testPassword()
1374 $form = $this->factory
->createNamed('name', 'password', 'foo&bar');
1376 $this->assertWidgetMatchesXpath($form->createView(), array(),
1384 public function testPasswordSubmittedWithNotAlwaysEmpty()
1386 $form = $this->factory
->createNamed('name', 'password', null, array(
1387 'always_empty' => false,
1389 $form->submit('foo&bar');
1391 $this->assertWidgetMatchesXpath($form->createView(), array(),
1400 public function testPasswordWithMaxLength()
1402 $form = $this->factory
->createNamed('name', 'password', 'foo&bar', array(
1403 'max_length' => 123,
1406 $this->assertWidgetMatchesXpath($form->createView(), array(),
1415 public function testPercent()
1417 $form = $this->factory
->createNamed('name', 'percent', 0.1);
1419 $this->assertWidgetMatchesXpath($form->createView(), array(),
1429 public function testCheckedRadio()
1431 $form = $this->factory
->createNamed('name', 'radio', true);
1433 $this->assertWidgetMatchesXpath($form->createView(), array(),
1437 [@checked="checked"]
1443 public function testUncheckedRadio()
1445 $form = $this->factory
->createNamed('name', 'radio', false);
1447 $this->assertWidgetMatchesXpath($form->createView(), array(),
1456 public function testRadioWithValue()
1458 $form = $this->factory
->createNamed('name', 'radio', false, array(
1459 'value' => 'foo&bar',
1462 $this->assertWidgetMatchesXpath($form->createView(), array(),
1471 public function testTextarea()
1473 $form = $this->factory
->createNamed('name', 'textarea', 'foo&bar', array(
1477 $this->assertWidgetMatchesXpath($form->createView(), array(),
1486 public function testText()
1488 $form = $this->factory
->createNamed('name', 'text', 'foo&bar');
1490 $this->assertWidgetMatchesXpath($form->createView(), array(),
1500 public function testTextWithMaxLength()
1502 $form = $this->factory
->createNamed('name', 'text', 'foo&bar', array(
1503 'max_length' => 123,
1506 $this->assertWidgetMatchesXpath($form->createView(), array(),
1516 public function testSearch()
1518 $form = $this->factory
->createNamed('name', 'search', 'foo&bar');
1520 $this->assertWidgetMatchesXpath($form->createView(), array(),
1530 public function testTime()
1532 $form = $this->factory
->createNamed('name', 'time', '04:05:06', array(
1533 'input' => 'string',
1534 'with_seconds' => false,
1537 $this->assertWidgetMatchesXpath($form->createView(), array(),
1543 [./option[@value="4"][@selected="selected"]]
1544 /following-sibling::select
1547 [./option[@value="5"][@selected="selected"]]
1554 public function testTimeWithSeconds()
1556 $form = $this->factory
->createNamed('name', 'time', '04:05:06', array(
1557 'input' => 'string',
1558 'with_seconds' => true,
1561 $this->assertWidgetMatchesXpath($form->createView(), array(),
1567 [./option[@value="4"][@selected="selected"]]
1568 [count(./option)>23]
1569 /following-sibling::select
1572 [./option[@value="5"][@selected="selected"]]
1573 [count(./option)>59]
1574 /following-sibling::select
1577 [./option[@value="6"][@selected="selected"]]
1578 [count(./option)>59]
1585 public function testTimeText()
1587 $form = $this->factory
->createNamed('name', 'time', '04:05:06', array(
1588 'input' => 'string',
1592 $this->assertWidgetMatchesXpath($form->createView(), array(),
1598 [@name="name[hour]"]
1601 [@required="required"]
1602 /following-sibling::input
1605 [@name="name[minute]"]
1608 [@required="required"]
1615 public function testTimeSingleText()
1617 $form = $this->factory
->createNamed('name', 'time', '04:05:06', array(
1618 'input' => 'string',
1619 'widget' => 'single_text',
1622 $this->assertWidgetMatchesXpath($form->createView(), array(),
1632 public function testTimeWithEmptyValueGlobal()
1634 $form = $this->factory
->createNamed('name', 'time', null, array(
1635 'input' => 'string',
1636 'empty_value' => 'Change&Me',
1637 'required' => false,
1640 $this->assertWidgetMatchesXpath($form->createView(), array(),
1645 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1646 [count(./option)>24]
1647 /following-sibling::select
1649 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1650 [count(./option)>60]
1657 public function testTimeWithEmptyValueOnYear()
1659 $form = $this->factory
->createNamed('name', 'time', null, array(
1660 'input' => 'string',
1661 'required' => false,
1662 'empty_value' => array('hour' => 'Change&Me'),
1665 $this->assertWidgetMatchesXpath($form->createView(), array(),
1670 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1671 [count(./option)>24]
1672 /following-sibling::select
1674 [./option[@value="1"]]
1675 [count(./option)>59]
1682 public function testTimeErrorBubbling()
1684 $form = $this->factory
->createNamedBuilder('form', 'form')
1685 ->add('time', 'time')
1687 $form->get('time')->addError(new FormError('[trans]Error![/trans]'));
1688 $view = $form->createView();
1690 $this->assertEmpty($this->renderErrors($view));
1691 $this->assertNotEmpty($this->renderErrors($view['time']));
1694 public function testTimezone()
1696 $form = $this->factory
->createNamed('name', 'timezone', 'Europe/Vienna');
1698 $this->assertWidgetMatchesXpath($form->createView(), array(),
1701 [@required="required"]
1703 [@label="[trans]Europe[/trans]"]
1704 [./option[@value="Europe/Vienna"][@selected="selected"][.="[trans]Vienna[/trans]"]]
1706 [count(./optgroup)>10]
1707 [count(.//option)>200]
1712 public function testTimezoneWithEmptyValue()
1714 $form = $this->factory
->createNamed('name', 'timezone', null, array(
1715 'empty_value' => 'Select&Timezone',
1716 'required' => false,
1719 $this->assertWidgetMatchesXpath($form->createView(), array(),
1721 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Timezone[/trans]"]]
1722 [count(./optgroup)>10]
1723 [count(.//option)>201]
1728 public function testUrl()
1730 $url = 'http://www.google.com?foo1=bar1&foo2=bar2';
1731 $form = $this->factory
->createNamed('name', 'url', $url);
1733 $this->assertWidgetMatchesXpath($form->createView(), array(),
1737 [@value="http://www.google.com?foo1=bar1&foo2=bar2"]
1742 public function testCollectionPrototype()
1744 $form = $this->factory
->createNamedBuilder('name', 'form', array('items' => array('one', 'two', 'three')))
1745 ->add('items', 'collection', array('allow_add' => true))
1749 $html = $this->renderWidget($form);
1751 $this->assertMatchesXpath($html,
1752 '//div[@id="name_items"][@data-prototype]
1754 //table[@id="name_items"][@data-prototype]'
1758 public function testEmptyRootFormName()
1760 $form = $this->factory
->createNamedBuilder('', 'form')
1761 ->add('child', 'text')
1764 $this->assertMatchesXpath($this->renderWidget($form->createView()),
1765 '//input[@type="hidden"][@id="_token"][@name="_token"]
1767 //input[@type="text"][@id="child"][@name="child"]'
1771 public function testButton()
1773 $form = $this->factory
->createNamed('name', 'button');
1775 $this->assertWidgetMatchesXpath($form->createView(), array(),
1776 '/button[@type="button"][@name="name"][.="[trans]Name[/trans]"]'
1780 public function testButtonLabelIsEmpty()
1782 $form = $this->factory
->createNamed('name', 'button');
1784 $this->assertSame('', $this->renderLabel($form->createView()));
1787 public function testSubmit()
1789 $form = $this->factory
->createNamed('name', 'submit');
1791 $this->assertWidgetMatchesXpath($form->createView(), array(),
1792 '/button[@type="submit"][@name="name"]'
1796 public function testReset()
1798 $form = $this->factory
->createNamed('name', 'reset');
1800 $this->assertWidgetMatchesXpath($form->createView(), array(),
1801 '/button[@type="reset"][@name="name"]'
1805 public function testStartTag()
1807 $form = $this->factory
->create('form', null, array(
1809 'action' => 'http://example.com/directory'
1812 $html = $this->renderStart($form->createView());
1814 $this->assertSame('<form method="get" action="http://example.com/directory">', $html);
1817 public function testStartTagForPutRequest()
1819 $form = $this->factory
->create('form', null, array(
1821 'action' => 'http://example.com/directory'
1824 $html = $this->renderStart($form->createView());
1826 $this->assertMatchesXpath($html . '</form>',
1828 [./input[@type="hidden"][@name="_method"][@value="PUT"]]
1830 [@action="http://example.com/directory"]'
1834 public function testStartTagWithOverriddenVars()
1836 $form = $this->factory
->create('form', null, array(
1838 'action' => 'http://example.com/directory',
1841 $html = $this->renderStart($form->createView(), array(
1843 'action' => 'http://foo.com/directory'
1846 $this->assertSame('<form method="post" action="http://foo.com/directory">', $html);
1849 public function testStartTagForMultipartForm()
1851 $form = $this->factory
->createBuilder('form', null, array(
1853 'action' => 'http://example.com/directory'
1855 ->add('file', 'file')
1858 $html = $this->renderStart($form->createView());
1860 $this->assertSame('<form method="get" action="http://example.com/directory" enctype="multipart/form-data">', $html);
1863 public function testStartTagWithExtraAttributes()
1865 $form = $this->factory
->create('form', null, array(
1867 'action' => 'http://example.com/directory'
1870 $html = $this->renderStart($form->createView(), array(
1871 'attr' => array('class' => 'foobar'),
1874 $this->assertSame('<form method="get" action="http://example.com/directory" class="foobar">', $html);