AbstractLayoutTest.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Tests\Component\Form;
  11. use Symfony\Component\Form\FormError;
  12. use Symfony\Component\Form\FormView;
  13. use Symfony\Component\Form\FormFactory;
  14. use Symfony\Component\Form\CsrfProvider\DefaultCsrfProvider;
  15. use Symfony\Component\Form\Type\Loader\DefaultTypeLoader;
  16. use Symfony\Component\EventDispatcher\EventDispatcher;
  17. abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
  18. {
  19. protected $csrfProvider;
  20. protected $factory;
  21. protected function setUp()
  22. {
  23. \Locale::setDefault('en');
  24. $dispatcher = new EventDispatcher();
  25. $validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
  26. $this->csrfProvider = $this->getMock('Symfony\Component\Form\CsrfProvider\CsrfProviderInterface');
  27. $storage = new \Symfony\Component\HttpFoundation\File\TemporaryStorage('foo', 1, \sys_get_temp_dir());
  28. $loader = new DefaultTypeLoader($validator, $this->csrfProvider , $storage);
  29. $this->factory = new FormFactory($loader);
  30. }
  31. protected function assertXpathNodeValue(\DomElement $element, $expression, $nodeValue)
  32. {
  33. $xpath = new \DOMXPath($element->ownerDocument);
  34. $nodeList = $xpath->evaluate($expression);
  35. $this->assertEquals(1, $nodeList->length);
  36. $this->assertEquals($nodeValue, $nodeList->item(0)->nodeValue);
  37. }
  38. protected function assertMatchesXpath($html, $expression, $count = 1)
  39. {
  40. $dom = new \DomDocument('UTF-8');
  41. try {
  42. // Wrap in <root> node so we can load HTML with multiple tags at
  43. // the top level
  44. $dom->loadXml('<root>'.$html.'</root>');
  45. } catch (\Exception $e) {
  46. return $this->fail(sprintf(
  47. "Failed loading HTML:\n\n%s\n\nError: %s",
  48. $html,
  49. $e->getMessage()
  50. ));
  51. }
  52. $xpath = new \DOMXPath($dom);
  53. $nodeList = $xpath->evaluate('/root'.$expression);
  54. if ($nodeList->length != $count) {
  55. $dom->formatOutput = true;
  56. $this->fail(sprintf(
  57. "Failed asserting that \n\n%s\n\nmatches exactly %s. Matches %s in \n\n%s",
  58. $expression,
  59. $count == 1 ? 'once' : $count . ' times',
  60. $nodeList->length == 1 ? 'once' : $nodeList->length . ' times',
  61. // strip away <root> and </root>
  62. substr($dom->saveHTML(), 6, -8)
  63. ));
  64. }
  65. }
  66. protected function assertWidgetMatchesXpath(FormView $view, array $vars, $xpath)
  67. {
  68. // include ampersands everywhere to validate escaping
  69. $html = $this->renderWidget($view, array_merge(array(
  70. 'id' => 'my&id',
  71. 'attr' => array('class' => 'my&class'),
  72. ), $vars));
  73. $xpath = trim($xpath).'
  74. [@id="my&id"]
  75. [@class="my&class"]';
  76. $this->assertMatchesXpath($html, $xpath);
  77. }
  78. abstract protected function renderEnctype(FormView $view);
  79. abstract protected function renderLabel(FormView $view, $label = null);
  80. abstract protected function renderErrors(FormView $view);
  81. abstract protected function renderWidget(FormView $view, array $vars = array());
  82. abstract protected function renderRow(FormView $view, array $vars = array());
  83. abstract protected function renderRest(FormView $view, array $vars = array());
  84. public function testEnctype()
  85. {
  86. $form = $this->factory->createNamedBuilder('form', 'na&me', null, array(
  87. 'property_path' => 'name',
  88. ))
  89. ->add('file', 'file')
  90. ->getForm();
  91. $this->assertEquals('enctype="multipart/form-data"', $this->renderEnctype($form->createView()));
  92. }
  93. public function testNoEnctype()
  94. {
  95. $form = $this->factory->createNamedBuilder('form', 'na&me', null, array(
  96. 'property_path' => 'name',
  97. ))
  98. ->add('text', 'text')
  99. ->getForm();
  100. $this->assertEquals('', $this->renderEnctype($form->createView()));
  101. }
  102. public function testLabel()
  103. {
  104. $form = $this->factory->createNamed('text', 'na&me', null, array(
  105. 'property_path' => 'name',
  106. ));
  107. $html = $this->renderLabel($form->createView());
  108. $this->assertMatchesXpath($html,
  109. '/label
  110. [@for="na&me"]
  111. [.="[trans]Na&me[/trans]"]
  112. '
  113. );
  114. }
  115. public function testLabelWithCustomTextPassedAsOption()
  116. {
  117. $form = $this->factory->createNamed('text', 'na&me', null, array(
  118. 'property_path' => 'name',
  119. 'label' => 'Custom label',
  120. ));
  121. $html = $this->renderLabel($form->createView());
  122. $this->assertMatchesXpath($html,
  123. '/label
  124. [@for="na&me"]
  125. [.="[trans]Custom label[/trans]"]
  126. '
  127. );
  128. }
  129. public function testLabelWithCustomTextPassedDirectly()
  130. {
  131. $form = $this->factory->createNamed('text', 'na&me', null, array(
  132. 'property_path' => 'name',
  133. ));
  134. $html = $this->renderLabel($form->createView(), 'Custom label');
  135. $this->assertMatchesXpath($html,
  136. '/label
  137. [@for="na&me"]
  138. [.="[trans]Custom label[/trans]"]
  139. '
  140. );
  141. }
  142. public function testErrors()
  143. {
  144. $form = $this->factory->createNamed('text', 'na&me', null, array(
  145. 'property_path' => 'name',
  146. ));
  147. $form->addError(new FormError('Error 1'));
  148. $form->addError(new FormError('Error 2'));
  149. $view = $form->createView();
  150. $html = $this->renderErrors($view);
  151. $this->assertMatchesXpath($html,
  152. '/ul
  153. [
  154. ./li[.="[trans]Error 1[/trans]"]
  155. /following-sibling::li[.="[trans]Error 2[/trans]"]
  156. ]
  157. [count(./li)=2]
  158. '
  159. );
  160. }
  161. public function testCheckedCheckbox()
  162. {
  163. $form = $this->factory->createNamed('checkbox', 'na&me', true, array(
  164. 'property_path' => 'name',
  165. ));
  166. $this->assertWidgetMatchesXpath($form->createView(), array(),
  167. '/input
  168. [@type="checkbox"]
  169. [@name="na&me"]
  170. [@checked="checked"]
  171. [@value="1"]
  172. '
  173. );
  174. }
  175. public function testCheckedCheckboxWithValue()
  176. {
  177. $form = $this->factory->createNamed('checkbox', 'na&me', true, array(
  178. 'property_path' => 'name',
  179. 'value' => 'foo&bar',
  180. ));
  181. $this->assertWidgetMatchesXpath($form->createView(), array(),
  182. '/input
  183. [@type="checkbox"]
  184. [@name="na&me"]
  185. [@checked="checked"]
  186. [@value="foo&bar"]
  187. '
  188. );
  189. }
  190. public function testUncheckedCheckbox()
  191. {
  192. $form = $this->factory->createNamed('checkbox', 'na&me', false, array(
  193. 'property_path' => 'name',
  194. ));
  195. $this->assertWidgetMatchesXpath($form->createView(), array(),
  196. '/input
  197. [@type="checkbox"]
  198. [@name="na&me"]
  199. [not(@checked)]
  200. '
  201. );
  202. }
  203. public function testSingleChoice()
  204. {
  205. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  206. 'property_path' => 'name',
  207. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  208. 'multiple' => false,
  209. 'expanded' => false,
  210. ));
  211. $this->assertWidgetMatchesXpath($form->createView(), array(),
  212. '/select
  213. [@name="na&me"]
  214. [
  215. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  216. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  217. ]
  218. [count(./option)=2]
  219. '
  220. );
  221. }
  222. public function testSingleChoiceWithPreferred()
  223. {
  224. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  225. 'property_path' => 'name',
  226. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  227. 'preferred_choices' => array('&b'),
  228. 'multiple' => false,
  229. 'expanded' => false,
  230. ));
  231. $this->assertWidgetMatchesXpath($form->createView(), array('separator' => '-- sep --'),
  232. '/select
  233. [@name="na&me"]
  234. [
  235. ./option[@value="&b"][not(@selected)][.="Choice&B"]
  236. /following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
  237. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  238. ]
  239. [count(./option)=3]
  240. '
  241. );
  242. }
  243. public function testSingleChoiceNonRequired()
  244. {
  245. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  246. 'property_path' => 'name',
  247. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  248. 'required' => false,
  249. 'multiple' => false,
  250. 'expanded' => false,
  251. ));
  252. $this->assertWidgetMatchesXpath($form->createView(), array(),
  253. '/select
  254. [@name="na&me"]
  255. [
  256. ./option[@value=""][.=""]
  257. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  258. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  259. ]
  260. [count(./option)=3]
  261. '
  262. );
  263. }
  264. public function testSingleChoiceGrouped()
  265. {
  266. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  267. 'property_path' => 'name',
  268. 'choices' => array(
  269. 'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  270. 'Group&2' => array('&c' => 'Choice&C'),
  271. ),
  272. 'multiple' => false,
  273. 'expanded' => false,
  274. ));
  275. $this->assertWidgetMatchesXpath($form->createView(), array(),
  276. '/select
  277. [@name="na&me"]
  278. [./optgroup[@label="Group&1"]
  279. [
  280. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  281. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  282. ]
  283. [count(./option)=2]
  284. ]
  285. [./optgroup[@label="Group&2"]
  286. [./option[@value="&c"][not(@selected)][.="Choice&C"]]
  287. [count(./option)=1]
  288. ]
  289. [count(./optgroup)=2]
  290. '
  291. );
  292. }
  293. public function testMultipleChoice()
  294. {
  295. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  296. 'property_path' => 'name',
  297. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  298. 'multiple' => true,
  299. 'expanded' => false,
  300. ));
  301. $this->assertWidgetMatchesXpath($form->createView(), array(),
  302. '/select
  303. [@name="na&me[]"]
  304. [@multiple="multiple"]
  305. [
  306. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  307. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  308. ]
  309. [count(./option)=2]
  310. '
  311. );
  312. }
  313. public function testMultipleChoiceNonRequired()
  314. {
  315. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  316. 'property_path' => 'name',
  317. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  318. 'required' => false,
  319. 'multiple' => true,
  320. 'expanded' => false,
  321. ));
  322. $this->assertWidgetMatchesXpath($form->createView(), array(),
  323. '/select
  324. [@name="na&me[]"]
  325. [@multiple="multiple"]
  326. [
  327. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  328. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  329. ]
  330. [count(./option)=2]
  331. '
  332. );
  333. }
  334. public function testSingleChoiceExpanded()
  335. {
  336. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  337. 'property_path' => 'name',
  338. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  339. 'multiple' => false,
  340. 'expanded' => true,
  341. ));
  342. $this->assertWidgetMatchesXpath($form->createView(), array(),
  343. '/div
  344. [
  345. ./input[@type="radio"][@name="na&me"][@id="na&me_&a"][@checked]
  346. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  347. /following-sibling::input[@type="radio"][@name="na&me"][@id="na&me_&b"][not(@checked)]
  348. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  349. ]
  350. [count(./input)=2]
  351. '
  352. );
  353. }
  354. public function testMultipleChoiceExpanded()
  355. {
  356. $form = $this->factory->createNamed('choice', 'na&me', array('&a', '&c'), array(
  357. 'property_path' => 'name',
  358. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
  359. 'multiple' => true,
  360. 'expanded' => true,
  361. 'required' => true,
  362. ));
  363. $this->assertWidgetMatchesXpath($form->createView(), array(),
  364. '/div
  365. [
  366. ./input[@type="checkbox"][@name="na&me[&a]"][@id="na&me_&a"][@checked][not(@required)]
  367. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  368. /following-sibling::input[@type="checkbox"][@name="na&me[&b]"][@id="na&me_&b"][not(@checked)][not(@required)]
  369. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  370. /following-sibling::input[@type="checkbox"][@name="na&me[&c]"][@id="na&me_&c"][@checked][not(@required)]
  371. /following-sibling::label[@for="na&me_&c"][.="[trans]Choice&C[/trans]"]
  372. ]
  373. [count(./input)=3]
  374. '
  375. );
  376. }
  377. public function testCountry()
  378. {
  379. $form = $this->factory->createNamed('country', 'na&me', 'AT', array(
  380. 'property_path' => 'name',
  381. ));
  382. $this->assertWidgetMatchesXpath($form->createView(), array(),
  383. '/select
  384. [@name="na&me"]
  385. [./option[@value="AT"][@selected="selected"][.="Austria"]]
  386. [count(./option)>200]
  387. '
  388. );
  389. }
  390. public function testCsrf()
  391. {
  392. $this->csrfProvider->expects($this->any())
  393. ->method('generateCsrfToken')
  394. ->will($this->returnValue('foo&bar'));
  395. $form = $this->factory->createNamed('csrf', 'na&me', null, array(
  396. 'property_path' => 'name',
  397. ));
  398. $this->assertWidgetMatchesXpath($form->createView(), array(),
  399. '/input
  400. [@type="hidden"]
  401. [@value="foo&bar"]
  402. '
  403. );
  404. }
  405. public function testCsrfWithNonRootParent()
  406. {
  407. $form = $this->factory->createNamed('csrf', 'na&me', null, array(
  408. 'property_path' => 'name',
  409. ));
  410. $form->setParent($this->factory->create('form'));
  411. $form->getParent()->setParent($this->factory->create('form'));
  412. $html = $this->renderWidget($form->createView());
  413. $this->assertEquals('', trim($html));
  414. }
  415. public function testDateTime()
  416. {
  417. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
  418. 'property_path' => 'name',
  419. 'input' => 'string',
  420. 'with_seconds' => false,
  421. ));
  422. $this->assertWidgetMatchesXpath($form->createView(), array(),
  423. '/div
  424. [
  425. ./div
  426. [@id="na&me_date"]
  427. [
  428. ./select
  429. [@id="na&me_date_month"]
  430. [./option[@value="2"][@selected="selected"]]
  431. /following-sibling::select
  432. [@id="na&me_date_day"]
  433. [./option[@value="3"][@selected="selected"]]
  434. /following-sibling::select
  435. [@id="na&me_date_year"]
  436. [./option[@value="2011"][@selected="selected"]]
  437. ]
  438. /following-sibling::div
  439. [@id="na&me_time"]
  440. [
  441. ./select
  442. [@id="na&me_time_hour"]
  443. [./option[@value="4"][@selected="selected"]]
  444. /following-sibling::select
  445. [@id="na&me_time_minute"]
  446. [./option[@value="5"][@selected="selected"]]
  447. ]
  448. ]
  449. [count(.//select)=5]
  450. '
  451. );
  452. }
  453. public function testDateTimeWithSeconds()
  454. {
  455. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
  456. 'property_path' => 'name',
  457. 'input' => 'string',
  458. 'with_seconds' => true,
  459. ));
  460. $this->assertWidgetMatchesXpath($form->createView(), array(),
  461. '/div
  462. [
  463. ./div
  464. [@id="na&me_date"]
  465. [
  466. ./select
  467. [@id="na&me_date_month"]
  468. [./option[@value="2"][@selected="selected"]]
  469. /following-sibling::select
  470. [@id="na&me_date_day"]
  471. [./option[@value="3"][@selected="selected"]]
  472. /following-sibling::select
  473. [@id="na&me_date_year"]
  474. [./option[@value="2011"][@selected="selected"]]
  475. ]
  476. /following-sibling::div
  477. [@id="na&me_time"]
  478. [
  479. ./select
  480. [@id="na&me_time_hour"]
  481. [./option[@value="4"][@selected="selected"]]
  482. /following-sibling::select
  483. [@id="na&me_time_minute"]
  484. [./option[@value="5"][@selected="selected"]]
  485. /following-sibling::select
  486. [@id="na&me_time_second"]
  487. [./option[@value="6"][@selected="selected"]]
  488. ]
  489. ]
  490. [count(.//select)=6]
  491. '
  492. );
  493. }
  494. public function testDateChoice()
  495. {
  496. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  497. 'property_path' => 'name',
  498. 'input' => 'string',
  499. 'widget' => 'choice',
  500. ));
  501. $this->assertWidgetMatchesXpath($form->createView(), array(),
  502. '/div
  503. [
  504. ./select
  505. [@id="na&me_month"]
  506. [./option[@value="2"][@selected="selected"]]
  507. /following-sibling::select
  508. [@id="na&me_day"]
  509. [./option[@value="3"][@selected="selected"]]
  510. /following-sibling::select
  511. [@id="na&me_year"]
  512. [./option[@value="2011"][@selected="selected"]]
  513. ]
  514. [count(./select)=3]
  515. '
  516. );
  517. }
  518. public function testDateText()
  519. {
  520. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  521. 'property_path' => 'name',
  522. 'input' => 'string',
  523. 'widget' => 'text',
  524. ));
  525. $this->assertWidgetMatchesXpath($form->createView(), array(),
  526. '/input
  527. [@type="text"]
  528. [@name="na&me"]
  529. [@value="Feb 3, 2011"]
  530. '
  531. );
  532. }
  533. public function testEmail()
  534. {
  535. $form = $this->factory->createNamed('email', 'na&me', 'foo&bar', array(
  536. 'property_path' => 'name',
  537. ));
  538. $this->assertWidgetMatchesXpath($form->createView(), array(),
  539. '/input
  540. [@type="email"]
  541. [@name="na&me"]
  542. [@value="foo&bar"]
  543. [not(@maxlength)]
  544. '
  545. );
  546. }
  547. public function testEmailWithMaxLength()
  548. {
  549. $form = $this->factory->createNamed('email', 'na&me', 'foo&bar', array(
  550. 'property_path' => 'name',
  551. 'max_length' => 123,
  552. ));
  553. $this->assertWidgetMatchesXpath($form->createView(), array(),
  554. '/input
  555. [@type="email"]
  556. [@name="na&me"]
  557. [@value="foo&bar"]
  558. [@maxlength="123"]
  559. '
  560. );
  561. }
  562. public function testFile()
  563. {
  564. $form = $this->factory->createNamed('file', 'na&me', null, array(
  565. 'property_path' => 'name',
  566. ));
  567. $this->assertWidgetMatchesXpath($form->createView(), array(),
  568. '/div
  569. [
  570. ./input[@type="file"][@id="na&me_file"]
  571. /following-sibling::input[@type="hidden"][@id="na&me_token"]
  572. /following-sibling::input[@type="hidden"][@id="na&me_name"]
  573. ]
  574. [count(./input)=3]
  575. '
  576. );
  577. }
  578. public function testHidden()
  579. {
  580. $form = $this->factory->createNamed('hidden', 'na&me', 'foo&bar', array(
  581. 'property_path' => 'name',
  582. ));
  583. $this->assertWidgetMatchesXpath($form->createView(), array(),
  584. '/input
  585. [@type="hidden"]
  586. [@name="na&me"]
  587. [@value="foo&bar"]
  588. '
  589. );
  590. }
  591. public function testInteger()
  592. {
  593. $form = $this->factory->createNamed('integer', 'na&me', 123, array(
  594. 'property_path' => 'name',
  595. ));
  596. $this->assertWidgetMatchesXpath($form->createView(), array(),
  597. '/input
  598. [@type="number"]
  599. [@name="na&me"]
  600. [@value="123"]
  601. '
  602. );
  603. }
  604. public function testLanguage()
  605. {
  606. $form = $this->factory->createNamed('language', 'na&me', 'de', array(
  607. 'property_path' => 'name',
  608. ));
  609. $this->assertWidgetMatchesXpath($form->createView(), array(),
  610. '/select
  611. [@name="na&me"]
  612. [./option[@value="de"][@selected="selected"][.="German"]]
  613. [count(./option)>200]
  614. '
  615. );
  616. }
  617. public function testLocale()
  618. {
  619. $form = $this->factory->createNamed('locale', 'na&me', 'de_AT', array(
  620. 'property_path' => 'name',
  621. ));
  622. $this->assertWidgetMatchesXpath($form->createView(), array(),
  623. '/select
  624. [@name="na&me"]
  625. [./option[@value="de_AT"][@selected="selected"][.="German (Austria)"]]
  626. [count(./option)>200]
  627. '
  628. );
  629. }
  630. public function testMoney()
  631. {
  632. $form = $this->factory->createNamed('money', 'na&me', 1234.56, array(
  633. 'property_path' => 'name',
  634. 'currency' => 'EUR',
  635. ));
  636. $this->assertWidgetMatchesXpath($form->createView(), array(),
  637. '/input
  638. [@type="text"]
  639. [@name="na&me"]
  640. [@value="1234.56"]
  641. [contains(.., "€")]
  642. '
  643. );
  644. }
  645. public function testNumber()
  646. {
  647. $form = $this->factory->createNamed('number', 'na&me', 1234.56, array(
  648. 'property_path' => 'name',
  649. ));
  650. $this->assertWidgetMatchesXpath($form->createView(), array(),
  651. '/input
  652. [@type="text"]
  653. [@name="na&me"]
  654. [@value="1234.56"]
  655. '
  656. );
  657. }
  658. public function testPassword()
  659. {
  660. $form = $this->factory->createNamed('password', 'na&me', 'foo&bar', array(
  661. 'property_path' => 'name',
  662. ));
  663. $this->assertWidgetMatchesXpath($form->createView(), array(),
  664. '/input
  665. [@type="password"]
  666. [@name="na&me"]
  667. [@value=""]
  668. '
  669. );
  670. }
  671. public function testPasswordBoundNotAlwaysEmpty()
  672. {
  673. $form = $this->factory->createNamed('password', 'na&me', null, array(
  674. 'property_path' => 'name',
  675. 'always_empty' => false,
  676. ));
  677. $form->bind('foo&bar');
  678. $this->assertWidgetMatchesXpath($form->createView(), array(),
  679. '/input
  680. [@type="password"]
  681. [@name="na&me"]
  682. [@value="foo&bar"]
  683. '
  684. );
  685. }
  686. public function testPasswordWithMaxLength()
  687. {
  688. $form = $this->factory->createNamed('password', 'na&me', 'foo&bar', array(
  689. 'property_path' => 'name',
  690. 'max_length' => 123,
  691. ));
  692. $this->assertWidgetMatchesXpath($form->createView(), array(),
  693. '/input
  694. [@type="password"]
  695. [@name="na&me"]
  696. [@value=""]
  697. [@maxlength="123"]
  698. '
  699. );
  700. }
  701. public function testPercent()
  702. {
  703. $form = $this->factory->createNamed('percent', 'na&me', 0.1, array(
  704. 'property_path' => 'name',
  705. ));
  706. $this->assertWidgetMatchesXpath($form->createView(), array(),
  707. '/input
  708. [@type="text"]
  709. [@name="na&me"]
  710. [@value="10"]
  711. [contains(.., "%")]
  712. '
  713. );
  714. }
  715. public function testCheckedRadio()
  716. {
  717. $form = $this->factory->createNamed('radio', 'na&me', true, array(
  718. 'property_path' => 'name',
  719. ));
  720. $this->assertWidgetMatchesXpath($form->createView(), array(),
  721. '/input
  722. [@type="radio"]
  723. [@name="na&me"]
  724. [@checked="checked"]
  725. [@value=""]
  726. '
  727. );
  728. }
  729. public function testCheckedRadioWithValue()
  730. {
  731. $form = $this->factory->createNamed('radio', 'na&me', true, array(
  732. 'property_path' => 'name',
  733. 'value' => 'foo&bar',
  734. ));
  735. $this->assertWidgetMatchesXpath($form->createView(), array(),
  736. '/input
  737. [@type="radio"]
  738. [@name="na&me"]
  739. [@checked="checked"]
  740. [@value="foo&bar"]
  741. '
  742. );
  743. }
  744. public function testUncheckedRadio()
  745. {
  746. $form = $this->factory->createNamed('radio', 'na&me', false, array(
  747. 'property_path' => 'name',
  748. ));
  749. $this->assertWidgetMatchesXpath($form->createView(), array(),
  750. '/input
  751. [@type="radio"]
  752. [@name="na&me"]
  753. [not(@checked)]
  754. '
  755. );
  756. }
  757. public function testTextarea()
  758. {
  759. $form = $this->factory->createNamed('textarea', 'na&me', 'foo&bar', array(
  760. 'property_path' => 'name',
  761. ));
  762. $this->assertWidgetMatchesXpath($form->createView(), array(),
  763. '/textarea
  764. [@name="na&me"]
  765. [.="foo&bar"]
  766. '
  767. );
  768. }
  769. public function testText()
  770. {
  771. $form = $this->factory->createNamed('text', 'na&me', 'foo&bar', array(
  772. 'property_path' => 'name',
  773. ));
  774. $this->assertWidgetMatchesXpath($form->createView(), array(),
  775. '/input
  776. [@type="text"]
  777. [@name="na&me"]
  778. [@value="foo&bar"]
  779. [not(@maxlength)]
  780. '
  781. );
  782. }
  783. public function testTextWithMaxLength()
  784. {
  785. $form = $this->factory->createNamed('text', 'na&me', 'foo&bar', array(
  786. 'property_path' => 'name',
  787. 'max_length' => 123,
  788. ));
  789. $this->assertWidgetMatchesXpath($form->createView(), array(),
  790. '/input
  791. [@type="text"]
  792. [@name="na&me"]
  793. [@value="foo&bar"]
  794. [@maxlength="123"]
  795. '
  796. );
  797. }
  798. public function testTime()
  799. {
  800. $form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
  801. 'property_path' => 'name',
  802. 'input' => 'string',
  803. 'with_seconds' => false,
  804. ));
  805. $this->assertWidgetMatchesXpath($form->createView(), array(),
  806. '/div
  807. [
  808. ./select
  809. [@id="na&me_hour"]
  810. [@size="1"]
  811. [./option[@value="4"][@selected="selected"]]
  812. /following-sibling::select
  813. [@id="na&me_minute"]
  814. [@size="1"]
  815. [./option[@value="5"][@selected="selected"]]
  816. ]
  817. [count(./select)=2]
  818. '
  819. );
  820. }
  821. public function testTimeWithSeconds()
  822. {
  823. $form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
  824. 'property_path' => 'name',
  825. 'input' => 'string',
  826. 'with_seconds' => true,
  827. ));
  828. $this->assertWidgetMatchesXpath($form->createView(), array(),
  829. '/div
  830. [
  831. ./select
  832. [@id="na&me_hour"]
  833. [@size="1"]
  834. [./option[@value="4"][@selected="selected"]]
  835. /following-sibling::select
  836. [@id="na&me_minute"]
  837. [@size="1"]
  838. [./option[@value="5"][@selected="selected"]]
  839. /following-sibling::select
  840. [@id="na&me_second"]
  841. [@size="1"]
  842. [./option[@value="6"][@selected="selected"]]
  843. ]
  844. [count(./select)=3]
  845. '
  846. );
  847. }
  848. public function testTimezone()
  849. {
  850. $form = $this->factory->createNamed('timezone', 'na&me', 'Europe/Vienna', array(
  851. 'property_path' => 'name',
  852. ));
  853. $this->assertWidgetMatchesXpath($form->createView(), array(),
  854. '/select
  855. [@name="na&me"]
  856. [./optgroup
  857. [@label="Europe"]
  858. [./option[@value="Europe/Vienna"][@selected="selected"][.="Vienna"]]
  859. ]
  860. [count(./optgroup)>10]
  861. [count(.//option)>200]
  862. '
  863. );
  864. }
  865. public function testUrl()
  866. {
  867. $url = 'http://www.google.com?foo1=bar1&foo2=bar2';
  868. $form = $this->factory->createNamed('url', 'na&me', $url, array(
  869. 'property_path' => 'name',
  870. ));
  871. $this->assertWidgetMatchesXpath($form->createView(), array(),
  872. '/input
  873. [@type="url"]
  874. [@name="na&me"]
  875. [@value="http://www.google.com?foo1=bar1&foo2=bar2"]
  876. '
  877. );
  878. }
  879. }