AbstractDivLayoutTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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. abstract class AbstractDivLayoutTest extends AbstractLayoutTest
  13. {
  14. public function testRow()
  15. {
  16. $form = $this->factory->createNamed('text', 'name');
  17. $form->addError(new FormError('Error!'));
  18. $view = $form->createView();
  19. $html = $this->renderRow($view);
  20. $this->assertMatchesXpath($html,
  21. '/div
  22. [
  23. ./label[@for="name"]
  24. /following-sibling::ul
  25. [./li[.="[trans]Error![/trans]"]]
  26. [count(./li)=1]
  27. /following-sibling::input[@id="name"]
  28. ]
  29. '
  30. );
  31. }
  32. public function testRowOverrideVariables()
  33. {
  34. $view = $this->factory->createNamed('text', 'name')->createView();
  35. $html = $this->renderRow($view, array(
  36. 'label' => array('label' => 'foo&bar', 'attr' => array('class ' => 'label&class')),
  37. 'widget' => array('attr' => array('class' => 'widget&class')),
  38. 'attr' => array('class' => 'row&class')
  39. ));
  40. $this->assertMatchesXpath($html,
  41. '/div[@class="row&class"]
  42. [
  43. ./label[@for="name"][.="[trans]foo&bar[/trans]"][@class="label&class"]
  44. /following-sibling::input[@id="name"][@class="widget&class"]
  45. ]
  46. '
  47. );
  48. }
  49. public function testRepeatedRow()
  50. {
  51. $form = $this->factory->createNamed('repeated', 'name');
  52. $form->addError(new FormError('Error!'));
  53. $view = $form->createView();
  54. $html = $this->renderRow($view);
  55. $this->assertMatchesXpath($html,
  56. '/ul
  57. [./li[.="[trans]Error![/trans]"]]
  58. [count(./li)=1]
  59. /following-sibling::div
  60. [
  61. ./label[@for="name_first"]
  62. /following-sibling::input[@id="name_first"]
  63. ]
  64. /following-sibling::div
  65. [
  66. ./label[@for="name_second"]
  67. /following-sibling::input[@id="name_second"]
  68. ]
  69. '
  70. );
  71. }
  72. public function testRest()
  73. {
  74. $view = $this->factory->createNamedBuilder('form', 'name')
  75. ->add('field1', 'text')
  76. ->add('field2', 'repeated')
  77. ->add('field3', 'text')
  78. ->add('field4', 'text')
  79. ->getForm()
  80. ->createView();
  81. // Render field2 row -> does not implicitly call renderWidget because
  82. // it is a repeated field!
  83. $this->renderRow($view['field2']);
  84. // Render field3 widget
  85. $this->renderWidget($view['field3']);
  86. // Rest should only contain field1 and field4
  87. $html = $this->renderRest($view);
  88. $this->assertMatchesXpath($html,
  89. '/input
  90. [@type="hidden"]
  91. [@id="name__token"]
  92. /following-sibling::div
  93. [
  94. ./label[@for="name_field1"]
  95. /following-sibling::input[@type="text"][@id="name_field1"]
  96. ]
  97. /following-sibling::div
  98. [
  99. ./label[@for="name_field4"]
  100. /following-sibling::input[@type="text"][@id="name_field4"]
  101. ]
  102. [count(../div)=2]
  103. [count(..//label)=2]
  104. [count(..//input)=3]
  105. '
  106. );
  107. }
  108. public function testRestWithChildrenForms()
  109. {
  110. $child1 = $this->factory->createNamedBuilder('form', 'child1')
  111. ->add('field1', 'text')
  112. ->add('field2', 'text')
  113. ->getForm();
  114. $child2 = $this->factory->createNamedBuilder('form', 'child2')
  115. ->add('field1', 'text')
  116. ->add('field2', 'text')
  117. ->getForm();
  118. $view = $this->factory->createNamedBuilder('form', 'parent')
  119. ->getForm()
  120. ->add($child1)
  121. ->add($child2)
  122. ->createView();
  123. // Render child1.field1 row
  124. $this->renderRow($view['child1']['field1']);
  125. // Render child2.field2 widget (remember that widget don't render label)
  126. $this->renderWidget($view['child2']['field2']);
  127. // Rest should only contain child1.field2 and child2.field1
  128. $html = $this->renderRest($view);
  129. $this->assertMatchesXpath($html,
  130. '/input[@type="hidden"][@id="parent__token"]
  131. /following-sibling::div
  132. [
  133. ./label[not(@for)]
  134. /following-sibling::div[@id="parent_child1"]
  135. [
  136. ./div
  137. [
  138. ./label[@for="parent_child1_field2"]
  139. /following-sibling::input[@id="parent_child1_field2"]
  140. ]
  141. ]
  142. ]
  143. /following-sibling::div
  144. [
  145. ./label[not(@for)]
  146. /following-sibling::div[@id="parent_child2"]
  147. [
  148. ./div
  149. [
  150. ./label[@for="parent_child2_field1"]
  151. /following-sibling::input[@id="parent_child2_field1"]
  152. ]
  153. ]
  154. ]
  155. [count(//label)=4]
  156. [count(//input[@type="text"])=2]
  157. '
  158. );
  159. }
  160. public function testRestAndRepeatedWithRow()
  161. {
  162. $view = $this->factory->createNamedBuilder('form', 'name')
  163. ->add('first', 'text')
  164. ->add('password', 'repeated')
  165. ->getForm()
  166. ->createView();
  167. $this->renderRow($view['password']);
  168. $html = $this->renderRest($view);
  169. $this->assertMatchesXpath($html,
  170. '/input
  171. [@type="hidden"]
  172. [@id="name__token"]
  173. /following-sibling::div
  174. [
  175. ./label[@for="name_first"]
  176. /following-sibling::input[@type="text"][@id="name_first"]
  177. ]
  178. [count(.//input)=1]
  179. '
  180. );
  181. }
  182. public function testRestAndRepeatedWithRowPerField()
  183. {
  184. $view = $this->factory->createNamedBuilder('form', 'name')
  185. ->add('first', 'text')
  186. ->add('password', 'repeated')
  187. ->getForm()
  188. ->createView();
  189. $this->renderRow($view['password']['first']);
  190. $this->renderRow($view['password']['second']);
  191. $html = $this->renderRest($view);
  192. $this->assertMatchesXpath($html,
  193. '/input
  194. [@type="hidden"]
  195. [@id="name__token"]
  196. /following-sibling::div
  197. [
  198. ./label[@for="name_first"]
  199. /following-sibling::input[@type="text"][@id="name_first"]
  200. ]
  201. [count(.//input)=1]
  202. [count(.//label)=1]
  203. '
  204. );
  205. }
  206. public function testRestAndRepeatedWithWidgetPerField()
  207. {
  208. $view = $this->factory->createNamedBuilder('form', 'name')
  209. ->add('first', 'text')
  210. ->add('password', 'repeated')
  211. ->getForm()
  212. ->createView();
  213. // The password form is considered as rendered as all its childrend
  214. // are rendered
  215. $this->renderWidget($view['password']['first']);
  216. $this->renderWidget($view['password']['second']);
  217. $html = $this->renderRest($view);
  218. $this->assertMatchesXpath($html,
  219. '/input
  220. [@type="hidden"]
  221. [@id="name__token"]
  222. /following-sibling::div
  223. [
  224. ./label[@for="name_first"]
  225. /following-sibling::input[@type="text"][@id="name_first"]
  226. ]
  227. [count(//input)=2]
  228. [count(//label)=1]
  229. '
  230. );
  231. }
  232. public function testCollection()
  233. {
  234. $form = $this->factory->createNamed('collection', 'name', array('a', 'b'), array(
  235. 'type' => 'text',
  236. ));
  237. $this->assertWidgetMatchesXpath($form->createView(), array(),
  238. '/div
  239. [
  240. ./div[./input[@type="text"][@value="a"]]
  241. /following-sibling::div[./input[@type="text"][@value="b"]]
  242. ]
  243. [count(./div[./input])=2]
  244. '
  245. );
  246. }
  247. public function testCollectionRow()
  248. {
  249. $collection = $this->factory->createNamedBuilder(
  250. 'collection',
  251. 'collection',
  252. array('a', 'b'),
  253. array('type' => 'text')
  254. );
  255. $form = $this->factory->createNamedBuilder('form', 'form')
  256. ->add($collection)
  257. ->getForm();
  258. $this->assertWidgetMatchesXpath($form->createView(), array(),
  259. '/div
  260. [
  261. ./input[@type="hidden"][@id="form__token"]
  262. /following-sibling::div
  263. [
  264. ./label[not(@for)]
  265. /following-sibling::div
  266. [
  267. ./div
  268. [
  269. ./label[@for="form_collection_0"]
  270. /following-sibling::input[@type="text"][@value="a"]
  271. ]
  272. /following-sibling::div
  273. [
  274. ./label[@for="form_collection_1"]
  275. /following-sibling::input[@type="text"][@value="b"]
  276. ]
  277. ]
  278. ]
  279. ]
  280. [count(.//input)=3]
  281. '
  282. );
  283. }
  284. public function testForm()
  285. {
  286. $form = $this->factory->createNamedBuilder('form', 'name')
  287. ->add('firstName', 'text')
  288. ->add('lastName', 'text')
  289. ->getForm();
  290. $this->assertWidgetMatchesXpath($form->createView(), array(),
  291. '/div
  292. [
  293. ./input[@type="hidden"][@id="name__token"]
  294. /following-sibling::div
  295. [
  296. ./label[@for="name_firstName"]
  297. /following-sibling::input[@type="text"][@id="name_firstName"]
  298. ]
  299. /following-sibling::div
  300. [
  301. ./label[@for="name_lastName"]
  302. /following-sibling::input[@type="text"][@id="name_lastName"]
  303. ]
  304. ]
  305. [count(.//input)=3]
  306. '
  307. );
  308. }
  309. public function testRepeated()
  310. {
  311. $form = $this->factory->createNamed('repeated', 'name', 'foobar', array(
  312. 'type' => 'text',
  313. ));
  314. $this->assertWidgetMatchesXpath($form->createView(), array(),
  315. '/div
  316. [
  317. ./div
  318. [
  319. ./label[@for="name_first"]
  320. /following-sibling::input[@type="text"][@id="name_first"]
  321. ]
  322. /following-sibling::div
  323. [
  324. ./label[@for="name_second"]
  325. /following-sibling::input[@type="text"][@id="name_second"]
  326. ]
  327. ]
  328. [count(.//input)=2]
  329. '
  330. );
  331. }
  332. public function testSearchInputName()
  333. {
  334. $form = $this->factory->createNamedBuilder('form', 'full')
  335. ->add('name', 'search')
  336. ->getForm();
  337. $this->assertWidgetMatchesXpath($form->createView(), array(),
  338. '/div
  339. [
  340. ./input[@type="hidden"][@id="full__token"]
  341. /following-sibling::div
  342. [
  343. ./label[@for="full_name"]
  344. /following-sibling::input[@type="search"][@id="full_name"][@name="full[name]"]
  345. ]
  346. ]
  347. [count(//input)=2]
  348. '
  349. );
  350. }
  351. public function testLabelHasNoId()
  352. {
  353. $form = $this->factory->createNamed('text', 'name');
  354. $html = $this->renderRow($form->createView());
  355. $this->assertMatchesXpath($html,
  356. '/div
  357. [
  358. ./label[@for="name"][not(@id)]
  359. /following-sibling::input[@id="name"]
  360. ]
  361. '
  362. );
  363. }
  364. public function testFileLabelAccessibility()
  365. {
  366. $form = $this->factory->createNamed('file', 'name');
  367. $html = $this->renderRow($form->createView());
  368. $this->assertMatchesXpath($html,
  369. '/div
  370. [
  371. ./label[@for="name"]
  372. /following-sibling::input[@id="name"][@type="file"]
  373. ]
  374. '
  375. );
  376. }
  377. }