AbstractLayoutTest.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101
  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, array $vars = array());
  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 testLabelWithCustomTextPassedAsOptionAndDirectly()
  144. {
  145. $form = $this->factory->createNamed('text', 'na&me', null, array(
  146. 'property_path' => 'name',
  147. 'label' => 'Custom label',
  148. ));
  149. $html = $this->renderLabel($form->createView(), 'Overridden label');
  150. $this->assertMatchesXpath($html,
  151. '/label
  152. [@for="na&me"]
  153. [.="[trans]Overridden label[/trans]"]
  154. '
  155. );
  156. }
  157. public function testLabelWithCustomOptionsPassedDirectly()
  158. {
  159. $form = $this->factory->createNamed('text', 'na&me', null, array(
  160. 'property_path' => 'name',
  161. ));
  162. $html = $this->renderLabel($form->createView(), null, array(
  163. 'attr' => array(
  164. 'class' => 'my&class'
  165. ),
  166. ));
  167. $this->assertMatchesXpath($html,
  168. '/label
  169. [@for="na&me"]
  170. [@class="my&class"]
  171. '
  172. );
  173. }
  174. public function testLabelWithCustomTextAndCustomOptionsPassedDirectly()
  175. {
  176. $form = $this->factory->createNamed('text', 'na&me', null, array(
  177. 'property_path' => 'name',
  178. ));
  179. $html = $this->renderLabel($form->createView(), 'Custom label', array(
  180. 'attr' => array(
  181. 'class' => 'my&class'
  182. ),
  183. ));
  184. $this->assertMatchesXpath($html,
  185. '/label
  186. [@for="na&me"]
  187. [@class="my&class"]
  188. [.="[trans]Custom label[/trans]"]
  189. '
  190. );
  191. }
  192. public function testErrors()
  193. {
  194. $form = $this->factory->createNamed('text', 'na&me', null, array(
  195. 'property_path' => 'name',
  196. ));
  197. $form->addError(new FormError('Error 1'));
  198. $form->addError(new FormError('Error 2'));
  199. $view = $form->createView();
  200. $html = $this->renderErrors($view);
  201. $this->assertMatchesXpath($html,
  202. '/ul
  203. [
  204. ./li[.="[trans]Error 1[/trans]"]
  205. /following-sibling::li[.="[trans]Error 2[/trans]"]
  206. ]
  207. [count(./li)=2]
  208. '
  209. );
  210. }
  211. public function testWidgetById()
  212. {
  213. $form = $this->factory->createNamed('text', 'text_id');
  214. $html = $this->renderWidget($form->createView());
  215. $this->assertMatchesXpath($html,
  216. '/div
  217. [
  218. ./input
  219. [@type="text"]
  220. [@id="text_id"]
  221. ]
  222. [@id="container"]
  223. '
  224. );
  225. }
  226. public function testCheckedCheckbox()
  227. {
  228. $form = $this->factory->createNamed('checkbox', 'na&me', true, array(
  229. 'property_path' => 'name',
  230. ));
  231. $this->assertWidgetMatchesXpath($form->createView(), array(),
  232. '/input
  233. [@type="checkbox"]
  234. [@name="na&me"]
  235. [@checked="checked"]
  236. [@value="1"]
  237. '
  238. );
  239. }
  240. public function testCheckedCheckboxWithValue()
  241. {
  242. $form = $this->factory->createNamed('checkbox', 'na&me', true, array(
  243. 'property_path' => 'name',
  244. 'value' => 'foo&bar',
  245. ));
  246. $this->assertWidgetMatchesXpath($form->createView(), array(),
  247. '/input
  248. [@type="checkbox"]
  249. [@name="na&me"]
  250. [@checked="checked"]
  251. [@value="foo&bar"]
  252. '
  253. );
  254. }
  255. public function testUncheckedCheckbox()
  256. {
  257. $form = $this->factory->createNamed('checkbox', 'na&me', false, array(
  258. 'property_path' => 'name',
  259. ));
  260. $this->assertWidgetMatchesXpath($form->createView(), array(),
  261. '/input
  262. [@type="checkbox"]
  263. [@name="na&me"]
  264. [not(@checked)]
  265. '
  266. );
  267. }
  268. public function testSingleChoice()
  269. {
  270. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  271. 'property_path' => 'name',
  272. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  273. 'multiple' => false,
  274. 'expanded' => false,
  275. ));
  276. $this->assertWidgetMatchesXpath($form->createView(), array(),
  277. '/select
  278. [@name="na&me"]
  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. );
  286. }
  287. public function testSingleChoiceWithPreferred()
  288. {
  289. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  290. 'property_path' => 'name',
  291. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  292. 'preferred_choices' => array('&b'),
  293. 'multiple' => false,
  294. 'expanded' => false,
  295. ));
  296. $this->assertWidgetMatchesXpath($form->createView(), array('separator' => '-- sep --'),
  297. '/select
  298. [@name="na&me"]
  299. [
  300. ./option[@value="&b"][not(@selected)][.="Choice&B"]
  301. /following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
  302. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  303. ]
  304. [count(./option)=3]
  305. '
  306. );
  307. }
  308. public function testSingleChoiceNonRequired()
  309. {
  310. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  311. 'property_path' => 'name',
  312. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  313. 'required' => false,
  314. 'multiple' => false,
  315. 'expanded' => false,
  316. ));
  317. $this->assertWidgetMatchesXpath($form->createView(), array(),
  318. '/select
  319. [@name="na&me"]
  320. [
  321. ./option[@value=""][.=""]
  322. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  323. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  324. ]
  325. [count(./option)=3]
  326. '
  327. );
  328. }
  329. public function testSingleChoiceGrouped()
  330. {
  331. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  332. 'property_path' => 'name',
  333. 'choices' => array(
  334. 'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  335. 'Group&2' => array('&c' => 'Choice&C'),
  336. ),
  337. 'multiple' => false,
  338. 'expanded' => false,
  339. ));
  340. $this->assertWidgetMatchesXpath($form->createView(), array(),
  341. '/select
  342. [@name="na&me"]
  343. [./optgroup[@label="Group&1"]
  344. [
  345. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  346. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  347. ]
  348. [count(./option)=2]
  349. ]
  350. [./optgroup[@label="Group&2"]
  351. [./option[@value="&c"][not(@selected)][.="Choice&C"]]
  352. [count(./option)=1]
  353. ]
  354. [count(./optgroup)=2]
  355. '
  356. );
  357. }
  358. public function testMultipleChoice()
  359. {
  360. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  361. 'property_path' => 'name',
  362. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  363. 'multiple' => true,
  364. 'expanded' => false,
  365. ));
  366. $this->assertWidgetMatchesXpath($form->createView(), array(),
  367. '/select
  368. [@name="na&me[]"]
  369. [@multiple="multiple"]
  370. [
  371. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  372. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  373. ]
  374. [count(./option)=2]
  375. '
  376. );
  377. }
  378. public function testMultipleChoiceNonRequired()
  379. {
  380. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  381. 'property_path' => 'name',
  382. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  383. 'required' => false,
  384. 'multiple' => true,
  385. 'expanded' => false,
  386. ));
  387. $this->assertWidgetMatchesXpath($form->createView(), array(),
  388. '/select
  389. [@name="na&me[]"]
  390. [@multiple="multiple"]
  391. [
  392. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  393. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  394. ]
  395. [count(./option)=2]
  396. '
  397. );
  398. }
  399. public function testSingleChoiceExpanded()
  400. {
  401. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  402. 'property_path' => 'name',
  403. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  404. 'multiple' => false,
  405. 'expanded' => true,
  406. ));
  407. $this->assertWidgetMatchesXpath($form->createView(), array(),
  408. '/div
  409. [
  410. ./input[@type="radio"][@name="na&me"][@id="na&me_&a"][@checked]
  411. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  412. /following-sibling::input[@type="radio"][@name="na&me"][@id="na&me_&b"][not(@checked)]
  413. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  414. ]
  415. [count(./input)=2]
  416. '
  417. );
  418. }
  419. public function testMultipleChoiceExpanded()
  420. {
  421. $form = $this->factory->createNamed('choice', 'na&me', array('&a', '&c'), array(
  422. 'property_path' => 'name',
  423. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
  424. 'multiple' => true,
  425. 'expanded' => true,
  426. 'required' => true,
  427. ));
  428. $this->assertWidgetMatchesXpath($form->createView(), array(),
  429. '/div
  430. [
  431. ./input[@type="checkbox"][@name="na&me[&a]"][@id="na&me_&a"][@checked][not(@required)]
  432. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  433. /following-sibling::input[@type="checkbox"][@name="na&me[&b]"][@id="na&me_&b"][not(@checked)][not(@required)]
  434. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  435. /following-sibling::input[@type="checkbox"][@name="na&me[&c]"][@id="na&me_&c"][@checked][not(@required)]
  436. /following-sibling::label[@for="na&me_&c"][.="[trans]Choice&C[/trans]"]
  437. ]
  438. [count(./input)=3]
  439. '
  440. );
  441. }
  442. public function testCountry()
  443. {
  444. $form = $this->factory->createNamed('country', 'na&me', 'AT', array(
  445. 'property_path' => 'name',
  446. ));
  447. $this->assertWidgetMatchesXpath($form->createView(), array(),
  448. '/select
  449. [@name="na&me"]
  450. [./option[@value="AT"][@selected="selected"][.="Austria"]]
  451. [count(./option)>200]
  452. '
  453. );
  454. }
  455. public function testCsrf()
  456. {
  457. $this->csrfProvider->expects($this->any())
  458. ->method('generateCsrfToken')
  459. ->will($this->returnValue('foo&bar'));
  460. $form = $this->factory->createNamed('csrf', 'na&me', null, array(
  461. 'property_path' => 'name',
  462. ));
  463. $this->assertWidgetMatchesXpath($form->createView(), array(),
  464. '/input
  465. [@type="hidden"]
  466. [@value="foo&bar"]
  467. '
  468. );
  469. }
  470. public function testDateTime()
  471. {
  472. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
  473. 'property_path' => 'name',
  474. 'input' => 'string',
  475. 'with_seconds' => false,
  476. ));
  477. $this->assertWidgetMatchesXpath($form->createView(), array(),
  478. '/div
  479. [
  480. ./div
  481. [@id="na&me_date"]
  482. [
  483. ./select
  484. [@id="na&me_date_month"]
  485. [./option[@value="2"][@selected="selected"]]
  486. /following-sibling::select
  487. [@id="na&me_date_day"]
  488. [./option[@value="3"][@selected="selected"]]
  489. /following-sibling::select
  490. [@id="na&me_date_year"]
  491. [./option[@value="2011"][@selected="selected"]]
  492. ]
  493. /following-sibling::div
  494. [@id="na&me_time"]
  495. [
  496. ./select
  497. [@id="na&me_time_hour"]
  498. [./option[@value="4"][@selected="selected"]]
  499. /following-sibling::select
  500. [@id="na&me_time_minute"]
  501. [./option[@value="5"][@selected="selected"]]
  502. ]
  503. ]
  504. [count(.//select)=5]
  505. '
  506. );
  507. }
  508. public function testDateTimeWithSeconds()
  509. {
  510. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
  511. 'property_path' => 'name',
  512. 'input' => 'string',
  513. 'with_seconds' => true,
  514. ));
  515. $this->assertWidgetMatchesXpath($form->createView(), array(),
  516. '/div
  517. [
  518. ./div
  519. [@id="na&me_date"]
  520. [
  521. ./select
  522. [@id="na&me_date_month"]
  523. [./option[@value="2"][@selected="selected"]]
  524. /following-sibling::select
  525. [@id="na&me_date_day"]
  526. [./option[@value="3"][@selected="selected"]]
  527. /following-sibling::select
  528. [@id="na&me_date_year"]
  529. [./option[@value="2011"][@selected="selected"]]
  530. ]
  531. /following-sibling::div
  532. [@id="na&me_time"]
  533. [
  534. ./select
  535. [@id="na&me_time_hour"]
  536. [./option[@value="4"][@selected="selected"]]
  537. /following-sibling::select
  538. [@id="na&me_time_minute"]
  539. [./option[@value="5"][@selected="selected"]]
  540. /following-sibling::select
  541. [@id="na&me_time_second"]
  542. [./option[@value="6"][@selected="selected"]]
  543. ]
  544. ]
  545. [count(.//select)=6]
  546. '
  547. );
  548. }
  549. public function testDateChoice()
  550. {
  551. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  552. 'property_path' => 'name',
  553. 'input' => 'string',
  554. 'widget' => 'choice',
  555. ));
  556. $this->assertWidgetMatchesXpath($form->createView(), array(),
  557. '/div
  558. [
  559. ./select
  560. [@id="na&me_month"]
  561. [./option[@value="2"][@selected="selected"]]
  562. /following-sibling::select
  563. [@id="na&me_day"]
  564. [./option[@value="3"][@selected="selected"]]
  565. /following-sibling::select
  566. [@id="na&me_year"]
  567. [./option[@value="2011"][@selected="selected"]]
  568. ]
  569. [count(./select)=3]
  570. '
  571. );
  572. }
  573. public function testDateText()
  574. {
  575. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  576. 'property_path' => 'name',
  577. 'input' => 'string',
  578. 'widget' => 'text',
  579. ));
  580. $this->assertWidgetMatchesXpath($form->createView(), array(),
  581. '/div
  582. [
  583. ./input
  584. [@id="na&me_month"]
  585. [@type="text"]
  586. [@value="2"]
  587. /following-sibling::input
  588. [@id="na&me_day"]
  589. [@type="text"]
  590. [@value="3"]
  591. /following-sibling::input
  592. [@id="na&me_year"]
  593. [@type="text"]
  594. [@value="2011"]
  595. ]
  596. [count(./input)=3]
  597. '
  598. );
  599. }
  600. public function testDateSingleText()
  601. {
  602. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  603. 'property_path' => 'name',
  604. 'input' => 'string',
  605. 'widget' => 'single_text',
  606. ));
  607. $this->assertWidgetMatchesXpath($form->createView(), array(),
  608. '/input
  609. [@type="text"]
  610. [@name="na&me"]
  611. [@value="Feb 3, 2011"]
  612. '
  613. );
  614. }
  615. public function testEmail()
  616. {
  617. $form = $this->factory->createNamed('email', 'na&me', 'foo&bar', array(
  618. 'property_path' => 'name',
  619. ));
  620. $this->assertWidgetMatchesXpath($form->createView(), array(),
  621. '/input
  622. [@type="email"]
  623. [@name="na&me"]
  624. [@value="foo&bar"]
  625. [not(@maxlength)]
  626. '
  627. );
  628. }
  629. public function testEmailWithMaxLength()
  630. {
  631. $form = $this->factory->createNamed('email', 'na&me', 'foo&bar', array(
  632. 'property_path' => 'name',
  633. 'max_length' => 123,
  634. ));
  635. $this->assertWidgetMatchesXpath($form->createView(), array(),
  636. '/input
  637. [@type="email"]
  638. [@name="na&me"]
  639. [@value="foo&bar"]
  640. [@maxlength="123"]
  641. '
  642. );
  643. }
  644. public function testFile()
  645. {
  646. $form = $this->factory->createNamed('file', 'na&me', null, array(
  647. 'property_path' => 'name',
  648. ));
  649. $this->assertWidgetMatchesXpath($form->createView(), array(),
  650. '/div
  651. [
  652. ./input[@type="file"][@id="na&me_file"]
  653. /following-sibling::input[@type="hidden"][@id="na&me_token"]
  654. /following-sibling::input[@type="hidden"][@id="na&me_name"]
  655. /following-sibling::input[@type="hidden"][@id="na&me_originalName"]
  656. ]
  657. [count(./input)=4]
  658. '
  659. );
  660. }
  661. public function testHidden()
  662. {
  663. $form = $this->factory->createNamed('hidden', 'na&me', 'foo&bar', array(
  664. 'property_path' => 'name',
  665. ));
  666. $this->assertWidgetMatchesXpath($form->createView(), array(),
  667. '/input
  668. [@type="hidden"]
  669. [@name="na&me"]
  670. [@value="foo&bar"]
  671. '
  672. );
  673. }
  674. public function testInteger()
  675. {
  676. $form = $this->factory->createNamed('integer', 'na&me', 123, array(
  677. 'property_path' => 'name',
  678. ));
  679. $this->assertWidgetMatchesXpath($form->createView(), array(),
  680. '/input
  681. [@type="number"]
  682. [@name="na&me"]
  683. [@value="123"]
  684. '
  685. );
  686. }
  687. public function testLanguage()
  688. {
  689. $form = $this->factory->createNamed('language', 'na&me', 'de', array(
  690. 'property_path' => 'name',
  691. ));
  692. $this->assertWidgetMatchesXpath($form->createView(), array(),
  693. '/select
  694. [@name="na&me"]
  695. [./option[@value="de"][@selected="selected"][.="German"]]
  696. [count(./option)>200]
  697. '
  698. );
  699. }
  700. public function testLocale()
  701. {
  702. $form = $this->factory->createNamed('locale', 'na&me', 'de_AT', array(
  703. 'property_path' => 'name',
  704. ));
  705. $this->assertWidgetMatchesXpath($form->createView(), array(),
  706. '/select
  707. [@name="na&me"]
  708. [./option[@value="de_AT"][@selected="selected"][.="German (Austria)"]]
  709. [count(./option)>200]
  710. '
  711. );
  712. }
  713. public function testMoney()
  714. {
  715. $form = $this->factory->createNamed('money', 'na&me', 1234.56, array(
  716. 'property_path' => 'name',
  717. 'currency' => 'EUR',
  718. ));
  719. $this->assertWidgetMatchesXpath($form->createView(), array(),
  720. '/input
  721. [@type="text"]
  722. [@name="na&me"]
  723. [@value="1234.56"]
  724. [contains(.., "€")]
  725. '
  726. );
  727. }
  728. public function testNumber()
  729. {
  730. $form = $this->factory->createNamed('number', 'na&me', 1234.56, array(
  731. 'property_path' => 'name',
  732. ));
  733. $this->assertWidgetMatchesXpath($form->createView(), array(),
  734. '/input
  735. [@type="text"]
  736. [@name="na&me"]
  737. [@value="1234.56"]
  738. '
  739. );
  740. }
  741. public function testPassword()
  742. {
  743. $form = $this->factory->createNamed('password', 'na&me', 'foo&bar', array(
  744. 'property_path' => 'name',
  745. ));
  746. $this->assertWidgetMatchesXpath($form->createView(), array(),
  747. '/input
  748. [@type="password"]
  749. [@name="na&me"]
  750. [@value=""]
  751. '
  752. );
  753. }
  754. public function testPasswordBoundNotAlwaysEmpty()
  755. {
  756. $form = $this->factory->createNamed('password', 'na&me', null, array(
  757. 'property_path' => 'name',
  758. 'always_empty' => false,
  759. ));
  760. $form->bind('foo&bar');
  761. $this->assertWidgetMatchesXpath($form->createView(), array(),
  762. '/input
  763. [@type="password"]
  764. [@name="na&me"]
  765. [@value="foo&bar"]
  766. '
  767. );
  768. }
  769. public function testPasswordWithMaxLength()
  770. {
  771. $form = $this->factory->createNamed('password', 'na&me', 'foo&bar', array(
  772. 'property_path' => 'name',
  773. 'max_length' => 123,
  774. ));
  775. $this->assertWidgetMatchesXpath($form->createView(), array(),
  776. '/input
  777. [@type="password"]
  778. [@name="na&me"]
  779. [@value=""]
  780. [@maxlength="123"]
  781. '
  782. );
  783. }
  784. public function testPercent()
  785. {
  786. $form = $this->factory->createNamed('percent', 'na&me', 0.1, array(
  787. 'property_path' => 'name',
  788. ));
  789. $this->assertWidgetMatchesXpath($form->createView(), array(),
  790. '/input
  791. [@type="text"]
  792. [@name="na&me"]
  793. [@value="10"]
  794. [contains(.., "%")]
  795. '
  796. );
  797. }
  798. public function testCheckedRadio()
  799. {
  800. $form = $this->factory->createNamed('radio', 'na&me', true, array(
  801. 'property_path' => 'name',
  802. ));
  803. $this->assertWidgetMatchesXpath($form->createView(), array(),
  804. '/input
  805. [@type="radio"]
  806. [@name="na&me"]
  807. [@checked="checked"]
  808. [@value=""]
  809. '
  810. );
  811. }
  812. public function testCheckedRadioWithValue()
  813. {
  814. $form = $this->factory->createNamed('radio', 'na&me', true, array(
  815. 'property_path' => 'name',
  816. 'value' => 'foo&bar',
  817. ));
  818. $this->assertWidgetMatchesXpath($form->createView(), array(),
  819. '/input
  820. [@type="radio"]
  821. [@name="na&me"]
  822. [@checked="checked"]
  823. [@value="foo&bar"]
  824. '
  825. );
  826. }
  827. public function testUncheckedRadio()
  828. {
  829. $form = $this->factory->createNamed('radio', 'na&me', false, array(
  830. 'property_path' => 'name',
  831. ));
  832. $this->assertWidgetMatchesXpath($form->createView(), array(),
  833. '/input
  834. [@type="radio"]
  835. [@name="na&me"]
  836. [not(@checked)]
  837. '
  838. );
  839. }
  840. public function testTextarea()
  841. {
  842. $form = $this->factory->createNamed('textarea', 'na&me', 'foo&bar', array(
  843. 'property_path' => 'name',
  844. ));
  845. $this->assertWidgetMatchesXpath($form->createView(), array(),
  846. '/textarea
  847. [@name="na&me"]
  848. [.="foo&bar"]
  849. '
  850. );
  851. }
  852. public function testText()
  853. {
  854. $form = $this->factory->createNamed('text', 'na&me', 'foo&bar', array(
  855. 'property_path' => 'name',
  856. ));
  857. $this->assertWidgetMatchesXpath($form->createView(), array(),
  858. '/input
  859. [@type="text"]
  860. [@name="na&me"]
  861. [@value="foo&bar"]
  862. [not(@maxlength)]
  863. '
  864. );
  865. }
  866. public function testTextWithMaxLength()
  867. {
  868. $form = $this->factory->createNamed('text', 'na&me', 'foo&bar', array(
  869. 'property_path' => 'name',
  870. 'max_length' => 123,
  871. ));
  872. $this->assertWidgetMatchesXpath($form->createView(), array(),
  873. '/input
  874. [@type="text"]
  875. [@name="na&me"]
  876. [@value="foo&bar"]
  877. [@maxlength="123"]
  878. '
  879. );
  880. }
  881. public function testSearch()
  882. {
  883. $form = $this->factory->createNamed('search', 'na&me', 'foo&bar', array(
  884. 'property_path' => 'name',
  885. ));
  886. $this->assertWidgetMatchesXpath($form->createView(), array(),
  887. '/input
  888. [@type="search"]
  889. [@name="na&me"]
  890. [@value="foo&bar"]
  891. [not(@maxlength)]
  892. '
  893. );
  894. }
  895. public function testTime()
  896. {
  897. $form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
  898. 'property_path' => 'name',
  899. 'input' => 'string',
  900. 'with_seconds' => false,
  901. ));
  902. $this->assertWidgetMatchesXpath($form->createView(), array(),
  903. '/div
  904. [
  905. ./select
  906. [@id="na&me_hour"]
  907. [@size="1"]
  908. [./option[@value="4"][@selected="selected"]]
  909. /following-sibling::select
  910. [@id="na&me_minute"]
  911. [@size="1"]
  912. [./option[@value="5"][@selected="selected"]]
  913. ]
  914. [count(./select)=2]
  915. '
  916. );
  917. }
  918. public function testTimeWithSeconds()
  919. {
  920. $form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
  921. 'property_path' => 'name',
  922. 'input' => 'string',
  923. 'with_seconds' => true,
  924. ));
  925. $this->assertWidgetMatchesXpath($form->createView(), array(),
  926. '/div
  927. [
  928. ./select
  929. [@id="na&me_hour"]
  930. [@size="1"]
  931. [./option[@value="4"][@selected="selected"]]
  932. /following-sibling::select
  933. [@id="na&me_minute"]
  934. [@size="1"]
  935. [./option[@value="5"][@selected="selected"]]
  936. /following-sibling::select
  937. [@id="na&me_second"]
  938. [@size="1"]
  939. [./option[@value="6"][@selected="selected"]]
  940. ]
  941. [count(./select)=3]
  942. '
  943. );
  944. }
  945. public function testTimezone()
  946. {
  947. $form = $this->factory->createNamed('timezone', 'na&me', 'Europe/Vienna', array(
  948. 'property_path' => 'name',
  949. ));
  950. $this->assertWidgetMatchesXpath($form->createView(), array(),
  951. '/select
  952. [@name="na&me"]
  953. [./optgroup
  954. [@label="Europe"]
  955. [./option[@value="Europe/Vienna"][@selected="selected"][.="Vienna"]]
  956. ]
  957. [count(./optgroup)>10]
  958. [count(.//option)>200]
  959. '
  960. );
  961. }
  962. public function testUrl()
  963. {
  964. $url = 'http://www.google.com?foo1=bar1&foo2=bar2';
  965. $form = $this->factory->createNamed('url', 'na&me', $url, array(
  966. 'property_path' => 'name',
  967. ));
  968. $this->assertWidgetMatchesXpath($form->createView(), array(),
  969. '/input
  970. [@type="url"]
  971. [@name="na&me"]
  972. [@value="http://www.google.com?foo1=bar1&foo2=bar2"]
  973. '
  974. );
  975. }
  976. }