This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
symfony/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php
Fabien Potencier 517f8e0162 merged branch bschussek/issue3839 (PR #3859)
Commits
-------

61d792e [Form] Changed checkboxes in an expanded multiple-choice field to not include the choice index
bc9bc4a [Form] Fixed behavior of expanded multiple-choice field when submitted without ticks
2e07256 [Form] Simplified choice list API
2645120 [Form] Fixed handling of expanded choice lists, checkboxes and radio buttons with empty values ("")

Discussion
----------

[Form] Fixed handling of empty values in checkbox/radio/choice type

Bug fix: yes
Feature addition: no
Backwards compatibility break: no
Symfony2 tests pass: yes
Fixes the following tickets: #3839, #3366
Todo: -

![Travis Build Status](https://secure.travis-ci.org/bschussek/symfony.png?branch=issue3839)

This PR fixes the processing of checkboxes and radio buttons with empty "value" attributes as well as of expanded choice forms with empty values. Additionally, some unnecessary complexity has been removed of the new ChoiceList API.

---------------------------------------------------------------------------

by stof at 2012-04-10T13:56:12Z

You probably need to change some things in the CHANGELOG file too

---------------------------------------------------------------------------

by bschussek at 2012-04-10T14:39:24Z

No. This is an update of a previous post-2.0 PR, the CHANGELOG is still accurate.

---------------------------------------------------------------------------

by stof at 2012-04-10T14:46:47Z

well, doesn't it require changes to the description of previous changes related to the ChoiceList ? It does in the UPGRADE file so it is weird if the CHANGELOG does not require any change.

---------------------------------------------------------------------------

by bschussek at 2012-04-10T14:56:05Z

Feel free to check yourself :)
2012-04-10 20:02:12 +02:00

1731 lines
48 KiB
PHP

<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Tests;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormFactory;
use Symfony\Component\Form\Extension\Core\CoreExtension;
use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
use Symfony\Component\EventDispatcher\EventDispatcher;
abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
{
protected $csrfProvider;
protected $factory;
protected function setUp()
{
if (!extension_loaded('intl')) {
$this->markTestSkipped('The "intl" extension is not available');
}
\Locale::setDefault('en');
$this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
$this->factory = new FormFactory(array(
new CoreExtension(),
new CsrfExtension($this->csrfProvider),
));
}
protected function tearDown()
{
$this->csrfProvider = null;
$this->factory = null;
}
protected function assertXpathNodeValue(\DomElement $element, $expression, $nodeValue)
{
$xpath = new \DOMXPath($element->ownerDocument);
$nodeList = $xpath->evaluate($expression);
$this->assertEquals(1, $nodeList->length);
$this->assertEquals($nodeValue, $nodeList->item(0)->nodeValue);
}
protected function assertMatchesXpath($html, $expression, $count = 1)
{
$dom = new \DomDocument('UTF-8');
try {
// Wrap in <root> node so we can load HTML with multiple tags at
// the top level
$dom->loadXml('<root>'.$html.'</root>');
} catch (\Exception $e) {
return $this->fail(sprintf(
"Failed loading HTML:\n\n%s\n\nError: %s",
$html,
$e->getMessage()
));
}
$xpath = new \DOMXPath($dom);
$nodeList = $xpath->evaluate('/root'.$expression);
if ($nodeList->length != $count) {
$dom->formatOutput = true;
$this->fail(sprintf(
"Failed asserting that \n\n%s\n\nmatches exactly %s. Matches %s in \n\n%s",
$expression,
$count == 1 ? 'once' : $count . ' times',
$nodeList->length == 1 ? 'once' : $nodeList->length . ' times',
// strip away <root> and </root>
substr($dom->saveHTML(), 6, -8)
));
}
}
protected function assertWidgetMatchesXpath(FormView $view, array $vars, $xpath)
{
// include ampersands everywhere to validate escaping
$html = $this->renderWidget($view, array_merge(array(
'id' => 'my&id',
'attr' => array('class' => 'my&class'),
), $vars));
$xpath = trim($xpath).'
[@id="my&id"]
[@class="my&class"]';
$this->assertMatchesXpath($html, $xpath);
}
abstract protected function renderEnctype(FormView $view);
abstract protected function renderLabel(FormView $view, $label = null, array $vars = array());
abstract protected function renderErrors(FormView $view);
abstract protected function renderWidget(FormView $view, array $vars = array());
abstract protected function renderRow(FormView $view, array $vars = array());
abstract protected function renderRest(FormView $view, array $vars = array());
abstract protected function setTheme(FormView $view, array $themes);
public function testEnctype()
{
$form = $this->factory->createNamedBuilder('form', 'name')
->add('file', 'file')
->getForm();
$this->assertEquals('enctype="multipart/form-data"', $this->renderEnctype($form->createView()));
}
public function testNoEnctype()
{
$form = $this->factory->createNamedBuilder('form', 'name')
->add('text', 'text')
->getForm();
$this->assertEquals('', $this->renderEnctype($form->createView()));
}
public function testLabel()
{
$form = $this->factory->createNamed('text', 'name');
$view = $form->createView();
$this->renderWidget($view, array('label' => 'foo'));
$html = $this->renderLabel($view);
$this->assertMatchesXpath($html,
'/label
[@for="name"]
[.="[trans]Name[/trans]"]
'
);
}
public function testLabelOnForm()
{
$form = $this->factory->createNamed('date', 'name');
$view = $form->createView();
$this->renderWidget($view, array('label' => 'foo'));
$html = $this->renderLabel($view);
$this->assertMatchesXpath($html,
'/label
[@class=" required"]
[.="[trans]Name[/trans]"]
'
);
}
public function testLabelWithCustomTextPassedAsOption()
{
$form = $this->factory->createNamed('text', 'name', null, array(
'label' => 'Custom label',
));
$html = $this->renderLabel($form->createView());
$this->assertMatchesXpath($html,
'/label
[@for="name"]
[.="[trans]Custom label[/trans]"]
'
);
}
public function testLabelWithCustomTextPassedDirectly()
{
$form = $this->factory->createNamed('text', 'name');
$html = $this->renderLabel($form->createView(), 'Custom label');
$this->assertMatchesXpath($html,
'/label
[@for="name"]
[.="[trans]Custom label[/trans]"]
'
);
}
public function testLabelWithCustomTextPassedAsOptionAndDirectly()
{
$form = $this->factory->createNamed('text', 'name', null, array(
'label' => 'Custom label',
));
$html = $this->renderLabel($form->createView(), 'Overridden label');
$this->assertMatchesXpath($html,
'/label
[@for="name"]
[.="[trans]Overridden label[/trans]"]
'
);
}
public function testLabelWithCustomOptionsPassedDirectly()
{
$form = $this->factory->createNamed('text', 'name');
$html = $this->renderLabel($form->createView(), null, array(
'attr' => array(
'class' => 'my&class'
),
));
$this->assertMatchesXpath($html,
'/label
[@for="name"]
[@class="my&class required"]
'
);
}
public function testLabelWithCustomTextAndCustomOptionsPassedDirectly()
{
$form = $this->factory->createNamed('text', 'name');
$html = $this->renderLabel($form->createView(), 'Custom label', array(
'attr' => array(
'class' => 'my&class'
),
));
$this->assertMatchesXpath($html,
'/label
[@for="name"]
[@class="my&class required"]
[.="[trans]Custom label[/trans]"]
'
);
}
public function testErrors()
{
$form = $this->factory->createNamed('text', 'name');
$form->addError(new FormError('Error 1'));
$form->addError(new FormError('Error 2'));
$view = $form->createView();
$html = $this->renderErrors($view);
$this->assertMatchesXpath($html,
'/ul
[
./li[.="[trans]Error 1[/trans]"]
/following-sibling::li[.="[trans]Error 2[/trans]"]
]
[count(./li)=2]
'
);
}
public function testWidgetById()
{
$form = $this->factory->createNamed('text', 'text_id');
$html = $this->renderWidget($form->createView());
$this->assertMatchesXpath($html,
'/div
[
./input
[@type="text"]
[@id="text_id"]
]
[@id="container"]
'
);
}
public function testCheckedCheckbox()
{
$form = $this->factory->createNamed('checkbox', 'name', true);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="checkbox"]
[@name="name"]
[@checked="checked"]
[@value="1"]
'
);
}
public function testUncheckedCheckbox()
{
$form = $this->factory->createNamed('checkbox', 'name', false);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="checkbox"]
[@name="name"]
[not(@checked)]
'
);
}
public function testCheckboxWithValue()
{
$form = $this->factory->createNamed('checkbox', 'name', false, array(
'value' => 'foo&bar',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="checkbox"]
[@name="name"]
[@value="foo&bar"]
'
);
}
public function testSingleChoice()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => false,
'expanded' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name"]
[@required="required"]
[
./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=2]
'
);
}
public function testSingleChoiceWithPreferred()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'preferred_choices' => array('&b'),
'multiple' => false,
'expanded' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array('separator' => '-- sep --'),
'/select
[@name="name"]
[@required="required"]
[
./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
]
[count(./option)=3]
'
);
}
public function testSingleChoiceWithPreferredAndNoSeparator()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'preferred_choices' => array('&b'),
'multiple' => false,
'expanded' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array('separator' => null),
'/select
[@name="name"]
[@required="required"]
[
./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
]
[count(./option)=2]
'
);
}
public function testSingleChoiceWithPreferredAndBlankSeparator()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'preferred_choices' => array('&b'),
'multiple' => false,
'expanded' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array('separator' => ''),
'/select
[@name="name"]
[@required="required"]
[
./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
/following-sibling::option[@disabled="disabled"][not(@selected)][.=""]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
]
[count(./option)=3]
'
);
}
public function testChoiceWithOnlyPreferred()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'preferred_choices' => array('&a', '&b'),
'multiple' => false,
'expanded' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[count(./option)=2]
'
);
}
public function testSingleChoiceNonRequired()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'required' => false,
'multiple' => false,
'expanded' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name"]
[not(@required)]
[
./option[@value=""][.="[trans][/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=3]
'
);
}
public function testSingleChoiceNonRequiredNoneSelected()
{
$form = $this->factory->createNamed('choice', 'name', null, array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'required' => false,
'multiple' => false,
'expanded' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name"]
[not(@required)]
[
./option[@value=""][.="[trans][/trans]"]
/following-sibling::option[@value="&a"][not(@selected)][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=3]
'
);
}
public function testSingleChoiceWithNonRequiredEmptyValue()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => false,
'expanded' => false,
'required' => false,
'empty_value' => 'Select&Anything&Not&Me',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name"]
[not(@required)]
[
./option[@value=""][not(@selected)][.="[trans]Select&Anything&Not&Me[/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=3]
'
);
}
public function testSingleChoiceRequiredWithEmptyValue()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'required' => true,
'multiple' => false,
'expanded' => false,
'empty_value' => 'Test&Me'
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name"]
[@required="required"]
[
./option[@value=""][.="[trans]Test&Me[/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=3]
'
);
}
public function testSingleChoiceRequiredWithEmptyValueViaView()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'required' => true,
'multiple' => false,
'expanded' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array('empty_value' => ''),
'/select
[@name="name"]
[@required="required"]
[
./option[@value=""][.="[trans][/trans]"]
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=3]
'
);
}
public function testSingleChoiceGrouped()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array(
'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'Group&2' => array('&c' => 'Choice&C'),
),
'multiple' => false,
'expanded' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name"]
[./optgroup[@label="[trans]Group&1[/trans]"]
[
./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=2]
]
[./optgroup[@label="[trans]Group&2[/trans]"]
[./option[@value="&c"][not(@selected)][.="[trans]Choice&C[/trans]"]]
[count(./option)=1]
]
[count(./optgroup)=2]
'
);
}
public function testMultipleChoice()
{
$form = $this->factory->createNamed('choice', 'name', array('&a'), array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => true,
'expanded' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name[]"]
[@multiple="multiple"]
[
./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=2]
'
);
}
public function testMultipleChoiceSkipEmptyValue()
{
$form = $this->factory->createNamed('choice', 'name', array('&a'), array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => true,
'expanded' => false,
'empty_value' => 'Test&Me'
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name[]"]
[@multiple="multiple"]
[
./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=2]
'
);
}
public function testMultipleChoiceNonRequired()
{
$form = $this->factory->createNamed('choice', 'name', array('&a'), array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'required' => false,
'multiple' => true,
'expanded' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name[]"]
[@multiple="multiple"]
[
./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
]
[count(./option)=2]
'
);
}
public function testSingleChoiceExpanded()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => false,
'expanded' => true,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
/following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
/following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
/following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
]
[count(./input)=2]
'
);
}
public function testSingleChoiceExpandedSkipEmptyValue()
{
$form = $this->factory->createNamed('choice', 'name', '&a', array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
'multiple' => false,
'expanded' => true,
'empty_value' => 'Test&Me'
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./input[@type="radio"][@name="name"][@id="name_0"][@checked]
/following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
/following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
/following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
]
[count(./input)=2]
'
);
}
public function testSingleChoiceExpandedWithBooleanValue()
{
$form = $this->factory->createNamed('choice', 'name', true, array(
'choices' => array('1' => 'Choice&A', '0' => 'Choice&B'),
'multiple' => false,
'expanded' => true,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./input[@type="radio"][@name="name"][@id="name_0"][@checked]
/following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
/following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
/following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
]
[count(./input)=2]
'
);
}
public function testMultipleChoiceExpanded()
{
$form = $this->factory->createNamed('choice', 'name', array('&a', '&c'), array(
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
'multiple' => true,
'expanded' => true,
'required' => true,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./input[@type="checkbox"][@name="name[]"][@id="name_0"][@checked][not(@required)]
/following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
/following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_1"][not(@checked)][not(@required)]
/following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
/following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_2"][@checked][not(@required)]
/following-sibling::label[@for="name_2"][.="[trans]Choice&C[/trans]"]
]
[count(./input)=3]
'
);
}
public function testCountry()
{
$form = $this->factory->createNamed('country', 'name', 'AT');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name"]
[./option[@value="AT"][@selected="selected"][.="[trans]Austria[/trans]"]]
[count(./option)>200]
'
);
}
public function testCountryWithEmptyValue()
{
$form = $this->factory->createNamed('country', 'name', 'AT', array(
'empty_value' => 'Select&Country',
'required' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name"]
[./option[@value=""][not(@selected)][.="[trans]Select&Country[/trans]"]]
[./option[@value="AT"][@selected="selected"][.="[trans]Austria[/trans]"]]
[count(./option)>201]
'
);
}
public function testCsrf()
{
$this->csrfProvider->expects($this->any())
->method('generateCsrfToken')
->will($this->returnValue('foo&bar'));
$form = $this->factory->createNamed('csrf', 'name');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="hidden"]
[@value="foo&bar"]
'
);
}
public function testDateTime()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
'input' => 'string',
'with_seconds' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./div
[@id="name_date"]
[
./select
[@id="name_date_month"]
[./option[@value="2"][@selected="selected"]]
/following-sibling::select
[@id="name_date_day"]
[./option[@value="3"][@selected="selected"]]
/following-sibling::select
[@id="name_date_year"]
[./option[@value="2011"][@selected="selected"]]
]
/following-sibling::div
[@id="name_time"]
[
./select
[@id="name_time_hour"]
[./option[@value="4"][@selected="selected"]]
/following-sibling::select
[@id="name_time_minute"]
[./option[@value="5"][@selected="selected"]]
]
]
[count(.//select)=5]
'
);
}
public function testDateTimeWithEmptyValueGlobal()
{
$form = $this->factory->createNamed('datetime', 'name', null, array(
'input' => 'string',
'empty_value' => 'Change&Me',
'required' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./div
[@id="name_date"]
[
./select
[@id="name_date_month"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
/following-sibling::select
[@id="name_date_day"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
/following-sibling::select
[@id="name_date_year"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
]
/following-sibling::div
[@id="name_time"]
[
./select
[@id="name_time_hour"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
/following-sibling::select
[@id="name_time_minute"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
]
]
[count(.//select)=5]
'
);
}
public function testDateTimeWithEmptyValueOnTime()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03', array(
'input' => 'string',
'empty_value' => array('hour' => 'Change&Me', 'minute' => 'Change&Me'),
'required' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./div
[@id="name_date"]
[
./select
[@id="name_date_month"]
[./option[@value="2"][@selected="selected"]]
/following-sibling::select
[@id="name_date_day"]
[./option[@value="3"][@selected="selected"]]
/following-sibling::select
[@id="name_date_year"]
[./option[@value="2011"][@selected="selected"]]
]
/following-sibling::div
[@id="name_time"]
[
./select
[@id="name_time_hour"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
/following-sibling::select
[@id="name_time_minute"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
]
]
[count(.//select)=5]
'
);
}
public function testDateTimeWithSeconds()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
'input' => 'string',
'with_seconds' => true,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./div
[@id="name_date"]
[
./select
[@id="name_date_month"]
[./option[@value="2"][@selected="selected"]]
/following-sibling::select
[@id="name_date_day"]
[./option[@value="3"][@selected="selected"]]
/following-sibling::select
[@id="name_date_year"]
[./option[@value="2011"][@selected="selected"]]
]
/following-sibling::div
[@id="name_time"]
[
./select
[@id="name_time_hour"]
[./option[@value="4"][@selected="selected"]]
/following-sibling::select
[@id="name_time_minute"]
[./option[@value="5"][@selected="selected"]]
/following-sibling::select
[@id="name_time_second"]
[./option[@value="6"][@selected="selected"]]
]
]
[count(.//select)=6]
'
);
}
public function testDateTimeSingleText()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
'input' => 'string',
'date_widget' => 'single_text',
'time_widget' => 'single_text',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./input
[@type="text"]
[@id="name_date"]
[@name="name[date]"]
[@value="Feb 3, 2011"]
/following-sibling::input
[@type="text"]
[@id="name_time"]
[@name="name[time]"]
[@value="04:05"]
]
'
);
}
public function testDateTimeWithWidgetSingleText()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
'input' => 'string',
'widget' => 'single_text',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="text"]
[@name="name"]
[@value="2011-02-03 04:05"]
'
);
}
public function testDateTimeWithWidgetSingleTextIgnoreDateAndTimeWidgets()
{
$form = $this->factory->createNamed('datetime', 'name', '2011-02-03 04:05:06', array(
'input' => 'string',
'date_widget' => 'choice',
'time_widget' => 'choice',
'widget' => 'single_text',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="text"]
[@name="name"]
[@value="2011-02-03 04:05"]
'
);
}
public function testDateChoice()
{
$form = $this->factory->createNamed('date', 'name', '2011-02-03', array(
'input' => 'string',
'widget' => 'choice',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./select
[@id="name_month"]
[./option[@value="2"][@selected="selected"]]
/following-sibling::select
[@id="name_day"]
[./option[@value="3"][@selected="selected"]]
/following-sibling::select
[@id="name_year"]
[./option[@value="2011"][@selected="selected"]]
]
[count(./select)=3]
'
);
}
public function testDateChoiceWithEmptyValueGlobal()
{
$form = $this->factory->createNamed('date', 'name', null, array(
'input' => 'string',
'widget' => 'choice',
'empty_value' => 'Change&Me',
'required' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./select
[@id="name_month"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
/following-sibling::select
[@id="name_day"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
/following-sibling::select
[@id="name_year"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
]
[count(./select)=3]
'
);
}
public function testDateChoiceWithEmptyValueOnYear()
{
$form = $this->factory->createNamed('date', 'name', null, array(
'input' => 'string',
'widget' => 'choice',
'required' => false,
'empty_value' => array('year' => 'Change&Me'),
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./select
[@id="name_month"]
[./option[@value="1"]]
/following-sibling::select
[@id="name_day"]
[./option[@value="1"]]
/following-sibling::select
[@id="name_year"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
]
[count(./select)=3]
'
);
}
public function testDateText()
{
$form = $this->factory->createNamed('date', 'name', '2011-02-03', array(
'input' => 'string',
'widget' => 'text',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./input
[@id="name_month"]
[@type="text"]
[@value="2"]
/following-sibling::input
[@id="name_day"]
[@type="text"]
[@value="3"]
/following-sibling::input
[@id="name_year"]
[@type="text"]
[@value="2011"]
]
[count(./input)=3]
'
);
}
public function testDateSingleText()
{
$form = $this->factory->createNamed('date', 'name', '2011-02-03', array(
'input' => 'string',
'widget' => 'single_text',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="text"]
[@name="name"]
[@value="Feb 3, 2011"]
'
);
}
public function testDateErrorBubbling()
{
$child = $this->factory->createNamed('date', 'date');
$form = $this->factory->createNamed('form', 'form')->add($child);
$child->addError(new FormError('Error!'));
$view = $form->createView();
$this->assertEmpty($this->renderErrors($view));
$this->assertNotEmpty($this->renderErrors($view['date']));
}
public function testBirthDay()
{
$form = $this->factory->createNamed('birthday', 'name', '2000-02-03', array(
'input' => 'string',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./select
[@id="name_month"]
[./option[@value="2"][@selected="selected"]]
/following-sibling::select
[@id="name_day"]
[./option[@value="3"][@selected="selected"]]
/following-sibling::select
[@id="name_year"]
[./option[@value="2000"][@selected="selected"]]
]
[count(./select)=3]
'
);
}
public function testBirthDayWithEmptyValue()
{
$form = $this->factory->createNamed('birthday', 'name', '1950-01-01', array(
'input' => 'string',
'empty_value' => '',
'required' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./select
[@id="name_month"]
[./option[@value=""][.="[trans][/trans]"]]
[./option[@value="1"][@selected="selected"]]
/following-sibling::select
[@id="name_day"]
[./option[@value=""][.="[trans][/trans]"]]
[./option[@value="1"][@selected="selected"]]
/following-sibling::select
[@id="name_year"]
[./option[@value=""][.="[trans][/trans]"]]
[./option[@value="1950"][@selected="selected"]]
]
[count(./select)=3]
'
);
}
public function testEmail()
{
$form = $this->factory->createNamed('email', 'name', 'foo&bar');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="email"]
[@name="name"]
[@value="foo&bar"]
[not(@maxlength)]
'
);
}
public function testEmailWithMaxLength()
{
$form = $this->factory->createNamed('email', 'name', 'foo&bar', array(
'max_length' => 123,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="email"]
[@name="name"]
[@value="foo&bar"]
[@maxlength="123"]
'
);
}
public function testFile()
{
$form = $this->factory->createNamed('file', 'name');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="file"]
'
);
}
public function testHidden()
{
$form = $this->factory->createNamed('hidden', 'name', 'foo&bar');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="hidden"]
[@name="name"]
[@value="foo&bar"]
'
);
}
public function testReadOnly()
{
$form = $this->factory->createNamed('text', 'name', null, array(
'read_only' => true,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="text"]
[@name="name"]
[@readonly="readonly"]
'
);
}
public function testDisabled()
{
$form = $this->factory->createNamed('text', 'name', null, array(
'disabled' => true,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="text"]
[@name="name"]
[@disabled="disabled"]
'
);
}
public function testInteger()
{
$form = $this->factory->createNamed('integer', 'name', 123);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="number"]
[@name="name"]
[@value="123"]
'
);
}
public function testLanguage()
{
$form = $this->factory->createNamed('language', 'name', 'de');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name"]
[./option[@value="de"][@selected="selected"][.="[trans]German[/trans]"]]
[count(./option)>200]
'
);
}
public function testLocale()
{
$form = $this->factory->createNamed('locale', 'name', 'de_AT');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name"]
[./option[@value="de_AT"][@selected="selected"][.="[trans]German (Austria)[/trans]"]]
[count(./option)>200]
'
);
}
public function testMoney()
{
$form = $this->factory->createNamed('money', 'name', 1234.56, array(
'currency' => 'EUR',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="text"]
[@name="name"]
[@value="1234.56"]
[contains(.., "€")]
'
);
}
public function testNumber()
{
$form = $this->factory->createNamed('number', 'name', 1234.56);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="text"]
[@name="name"]
[@value="1234.56"]
'
);
}
public function testPassword()
{
$form = $this->factory->createNamed('password', 'name', 'foo&bar');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="password"]
[@name="name"]
'
);
}
public function testPasswordBoundNotAlwaysEmpty()
{
$form = $this->factory->createNamed('password', 'name', null, array(
'always_empty' => false,
));
$form->bind('foo&bar');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="password"]
[@name="name"]
[@value="foo&bar"]
'
);
}
public function testPasswordWithMaxLength()
{
$form = $this->factory->createNamed('password', 'name', 'foo&bar', array(
'max_length' => 123,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="password"]
[@name="name"]
[@maxlength="123"]
'
);
}
public function testPercent()
{
$form = $this->factory->createNamed('percent', 'name', 0.1);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="text"]
[@name="name"]
[@value="10"]
[contains(.., "%")]
'
);
}
public function testCheckedRadio()
{
$form = $this->factory->createNamed('radio', 'name', true);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="radio"]
[@name="name"]
[@checked="checked"]
[@value="1"]
'
);
}
public function testUncheckedRadio()
{
$form = $this->factory->createNamed('radio', 'name', false);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="radio"]
[@name="name"]
[not(@checked)]
'
);
}
public function testRadioWithValue()
{
$form = $this->factory->createNamed('radio', 'name', false, array(
'value' => 'foo&bar',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="radio"]
[@name="name"]
[@value="foo&bar"]
'
);
}
public function testTextarea()
{
$form = $this->factory->createNamed('textarea', 'name', 'foo&bar', array(
'pattern' => 'foo',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/textarea
[@name="name"]
[not(@pattern)]
[.="foo&bar"]
'
);
}
public function testText()
{
$form = $this->factory->createNamed('text', 'name', 'foo&bar');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="text"]
[@name="name"]
[@value="foo&bar"]
[not(@maxlength)]
'
);
}
public function testTextWithMaxLength()
{
$form = $this->factory->createNamed('text', 'name', 'foo&bar', array(
'max_length' => 123,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="text"]
[@name="name"]
[@value="foo&bar"]
[@maxlength="123"]
'
);
}
public function testSearch()
{
$form = $this->factory->createNamed('search', 'name', 'foo&bar');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="search"]
[@name="name"]
[@value="foo&bar"]
[not(@maxlength)]
'
);
}
public function testTime()
{
$form = $this->factory->createNamed('time', 'name', '04:05:06', array(
'input' => 'string',
'with_seconds' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./select
[@id="name_hour"]
[@size="1"]
[./option[@value="4"][@selected="selected"]]
/following-sibling::select
[@id="name_minute"]
[@size="1"]
[./option[@value="5"][@selected="selected"]]
]
[count(./select)=2]
'
);
}
public function testTimeWithSeconds()
{
$form = $this->factory->createNamed('time', 'name', '04:05:06', array(
'input' => 'string',
'with_seconds' => true,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./select
[@id="name_hour"]
[@size="1"]
[./option[@value="4"][@selected="selected"]]
[count(./option)>23]
/following-sibling::select
[@id="name_minute"]
[@size="1"]
[./option[@value="5"][@selected="selected"]]
[count(./option)>59]
/following-sibling::select
[@id="name_second"]
[@size="1"]
[./option[@value="6"][@selected="selected"]]
[count(./option)>59]
]
[count(./select)=3]
'
);
}
public function testTimeText()
{
$form = $this->factory->createNamed('time', 'name', '04:05:06', array(
'input' => 'string',
'widget' => 'text',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./input
[@type="text"]
[@id="name_hour"]
[@name="name[hour]"]
[@value="04"]
[@size="1"]
[@required="required"]
/following-sibling::input
[@type="text"]
[@id="name_minute"]
[@name="name[minute]"]
[@value="05"]
[@size="1"]
[@required="required"]
]
[count(./input)=2]
'
);
}
public function testTimeSingleText()
{
$form = $this->factory->createNamed('time', 'name', '04:05:06', array(
'input' => 'string',
'widget' => 'single_text',
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="text"]
[@name="name"]
[@value="04:05"]
'
);
}
public function testTimeWithEmptyValueGlobal()
{
$form = $this->factory->createNamed('time', 'name', null, array(
'input' => 'string',
'empty_value' => 'Change&Me',
'required' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./select
[@id="name_hour"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
[count(./option)>24]
/following-sibling::select
[@id="name_minute"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
[count(./option)>60]
]
[count(./select)=2]
'
);
}
public function testTimeWithEmptyValueOnYear()
{
$form = $this->factory->createNamed('time', 'name', null, array(
'input' => 'string',
'required' => false,
'empty_value' => array('hour' => 'Change&Me'),
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/div
[
./select
[@id="name_hour"]
[./option[@value=""][.="[trans]Change&Me[/trans]"]]
[count(./option)>24]
/following-sibling::select
[@id="name_minute"]
[./option[@value="1"]]
[count(./option)>59]
]
[count(./select)=2]
'
);
}
public function testTimeErrorBubbling()
{
$child = $this->factory->createNamed('time', 'time');
$form = $this->factory->createNamed('form', 'form')->add($child);
$child->addError(new FormError('Error!'));
$view = $form->createView();
$this->assertEmpty($this->renderErrors($view));
$this->assertNotEmpty($this->renderErrors($view['time']));
}
public function testTimezone()
{
$form = $this->factory->createNamed('timezone', 'name', 'Europe/Vienna');
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[@name="name"]
[@required="required"]
[./optgroup
[@label="[trans]Europe[/trans]"]
[./option[@value="Europe/Vienna"][@selected="selected"][.="[trans]Vienna[/trans]"]]
]
[count(./optgroup)>10]
[count(.//option)>200]
'
);
}
public function testTimezoneWithEmptyValue()
{
$form = $this->factory->createNamed('timezone', 'name', null, array(
'empty_value' => 'Select&Timezone',
'required' => false,
));
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/select
[./option[@value=""][.="[trans]Select&Timezone[/trans]"]]
[count(./optgroup)>10]
[count(.//option)>201]
'
);
}
public function testUrl()
{
$url = 'http://www.google.com?foo1=bar1&foo2=bar2';
$form = $this->factory->createNamed('url', 'name', $url);
$this->assertWidgetMatchesXpath($form->createView(), array(),
'/input
[@type="url"]
[@name="name"]
[@value="http://www.google.com?foo1=bar1&foo2=bar2"]
'
);
}
public function testCollectionPrototype()
{
$form = $this->factory->createNamedBuilder('form', 'name', array('items' => array('one', 'two', 'three')))
->add('items', 'collection', array('allow_add' => true))
->getForm()
->createView();
$html = $this->renderWidget($form);
$this->assertMatchesXpath($html,
'//div[@id="name_items"][@data-prototype]
|
//table[@id="name_items"][@data-prototype]
'
);
}
public function testEmptyRootFormName()
{
$form = $this->factory->createNamedBuilder('form', '', '')
->add('child', 'text')
->getForm();
$this->assertMatchesXpath($this->renderWidget($form->createView()),
'//input[@type="hidden"][@id="_token"][@name="_token"]
|
//input[@type="text"][@id="child"][@name="child"]'
, 2);
}
}