AbstractLayoutTest.php 28 KB

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