AbstractLayoutTest.php 27 KB

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