RadioWidgetTest.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The MIT License
  8. * For full copyright and license information, please see the LICENSE.txt
  9. * Redistributions of files must retain the above copyright notice.
  10. *
  11. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  12. * @link https://cakephp.org CakePHP(tm) Project
  13. * @since 3.0.0
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\Test\TestCase\View\Widget;
  17. use Cake\Collection\Collection;
  18. use Cake\TestSuite\TestCase;
  19. use Cake\View\Form\NullContext;
  20. use Cake\View\StringTemplate;
  21. use Cake\View\Widget\NestingLabelWidget;
  22. use Cake\View\Widget\RadioWidget;
  23. /**
  24. * Radio test case
  25. */
  26. class RadioWidgetTest extends TestCase
  27. {
  28. /**
  29. * @var \Cake\View\Form\NullContext
  30. */
  31. protected $context;
  32. /**
  33. * @var \Cake\View\StringTemplate
  34. */
  35. protected $templates;
  36. /**
  37. * setup method.
  38. */
  39. public function setUp(): void
  40. {
  41. parent::setUp();
  42. $templates = [
  43. 'radio' => '<input type="radio" name="{{name}}" value="{{value}}"{{attrs}}>',
  44. 'nestingLabel' => '<label{{attrs}}>{{input}}{{text}}</label>',
  45. 'radioWrapper' => '{{label}}',
  46. 'selectedClass' => 'selected',
  47. ];
  48. $this->templates = new StringTemplate($templates);
  49. $this->context = new NullContext([]);
  50. }
  51. /**
  52. * Test rendering basic radio buttons without nested inputs
  53. */
  54. public function testRenderSimpleNotNested(): void
  55. {
  56. $this->templates->add([
  57. 'nestingLabel' => '<label{{attrs}}>{{text}}</label>',
  58. 'radioWrapper' => '{{input}}{{label}}',
  59. ]);
  60. $label = new NestingLabelWidget($this->templates);
  61. $radio = new RadioWidget($this->templates, $label);
  62. $data = [
  63. 'name' => 'Crayons[color]',
  64. 'label' => null,
  65. 'options' => ['r' => 'Red', 'b' => 'Black'],
  66. ];
  67. $result = $radio->render($data, $this->context);
  68. $expected = [
  69. ['input' => [
  70. 'type' => 'radio',
  71. 'name' => 'Crayons[color]',
  72. 'value' => 'r',
  73. 'id' => 'crayons-color-r',
  74. ]],
  75. ['label' => ['for' => 'crayons-color-r']],
  76. 'Red',
  77. '/label',
  78. ['input' => [
  79. 'type' => 'radio',
  80. 'name' => 'Crayons[color]',
  81. 'value' => 'b',
  82. 'id' => 'crayons-color-b',
  83. ]],
  84. ['label' => ['for' => 'crayons-color-b']],
  85. 'Black',
  86. '/label',
  87. ];
  88. $this->assertHtml($expected, $result);
  89. $data = [
  90. 'name' => 'Crayons[color]',
  91. 'label' => false,
  92. 'options' => ['r' => 'Red', 'b' => 'Black'],
  93. ];
  94. $result = $radio->render($data, $this->context);
  95. $expected = [
  96. ['input' => [
  97. 'type' => 'radio',
  98. 'name' => 'Crayons[color]',
  99. 'value' => 'r',
  100. 'id' => 'crayons-color-r',
  101. ]],
  102. ['input' => [
  103. 'type' => 'radio',
  104. 'name' => 'Crayons[color]',
  105. 'value' => 'b',
  106. 'id' => 'crayons-color-b',
  107. ]],
  108. ];
  109. $this->assertHtml($expected, $result);
  110. }
  111. /**
  112. * Test rendering basic radio buttons.
  113. */
  114. public function testRenderSimple(): void
  115. {
  116. $label = new NestingLabelWidget($this->templates);
  117. $radio = new RadioWidget($this->templates, $label);
  118. $data = [
  119. 'name' => 'Crayons[color]',
  120. 'label' => null,
  121. 'options' => ['r' => 'Red', 'b' => 'Black'],
  122. ];
  123. $result = $radio->render($data, $this->context);
  124. $expected = [
  125. ['label' => ['for' => 'crayons-color-r']],
  126. ['input' => [
  127. 'type' => 'radio',
  128. 'name' => 'Crayons[color]',
  129. 'value' => 'r',
  130. 'id' => 'crayons-color-r',
  131. ]],
  132. 'Red',
  133. '/label',
  134. ['label' => ['for' => 'crayons-color-b']],
  135. ['input' => [
  136. 'type' => 'radio',
  137. 'name' => 'Crayons[color]',
  138. 'value' => 'b',
  139. 'id' => 'crayons-color-b',
  140. ]],
  141. 'Black',
  142. '/label',
  143. ];
  144. $this->assertHtml($expected, $result);
  145. $data = [
  146. 'name' => 'Crayons[color]',
  147. 'options' => new Collection(['r' => 'Red', 'b' => 'Black']),
  148. ];
  149. $result = $radio->render($data, $this->context);
  150. $this->assertHtml($expected, $result);
  151. }
  152. /**
  153. * Test rendering the activeClass template var
  154. */
  155. public function testRenderSimpleActiveTemplateVar(): void
  156. {
  157. $this->templates->add([
  158. 'nestingLabel' => '<label class="{{activeClass}}"{{attrs}}>{{text}}</label>',
  159. 'radioWrapper' => '{{input}}{{label}}',
  160. ]);
  161. $label = new NestingLabelWidget($this->templates);
  162. $radio = new RadioWidget($this->templates, $label);
  163. $data = [
  164. 'name' => 'Crayons[color]',
  165. 'val' => 'r',
  166. 'options' => ['r' => 'Red', 'b' => 'Black'],
  167. ];
  168. $result = $radio->render($data, $this->context);
  169. $expected = [
  170. ['input' => [
  171. 'type' => 'radio',
  172. 'name' => 'Crayons[color]',
  173. 'value' => 'r',
  174. 'id' => 'crayons-color-r',
  175. 'checked' => 'checked',
  176. ]],
  177. ['label' => ['class' => 'active', 'for' => 'crayons-color-r']],
  178. 'Red',
  179. '/label',
  180. ['input' => [
  181. 'type' => 'radio',
  182. 'name' => 'Crayons[color]',
  183. 'value' => 'b',
  184. 'id' => 'crayons-color-b',
  185. ]],
  186. ['label' => ['class' => '', 'for' => 'crayons-color-b']],
  187. 'Black',
  188. '/label',
  189. ];
  190. $this->assertHtml($expected, $result);
  191. }
  192. /**
  193. * Test rendering inputs with the complex option form.
  194. */
  195. public function testRenderComplex(): void
  196. {
  197. $label = new NestingLabelWidget($this->templates);
  198. $radio = new RadioWidget($this->templates, $label);
  199. $data = [
  200. 'name' => 'Crayons[color]',
  201. 'options' => [
  202. ['value' => 'r', 'text' => 'Red', 'id' => 'my_id'],
  203. ['value' => 'b', 'text' => 'Black', 'id' => 'my_id_2', 'data-test' => 'test'],
  204. ],
  205. ];
  206. $result = $radio->render($data, $this->context);
  207. $expected = [
  208. ['label' => ['for' => 'my_id']],
  209. ['input' => [
  210. 'type' => 'radio',
  211. 'name' => 'Crayons[color]',
  212. 'value' => 'r',
  213. 'id' => 'my_id',
  214. ]],
  215. 'Red',
  216. '/label',
  217. ['label' => ['for' => 'my_id_2']],
  218. ['input' => [
  219. 'type' => 'radio',
  220. 'name' => 'Crayons[color]',
  221. 'value' => 'b',
  222. 'id' => 'my_id_2',
  223. 'data-test' => 'test',
  224. ]],
  225. 'Black',
  226. '/label',
  227. ];
  228. $this->assertHtml($expected, $result);
  229. }
  230. /**
  231. * Test rendering inputs with label options
  232. */
  233. public function testRenderComplexLabelAttributes(): void
  234. {
  235. $label = new NestingLabelWidget($this->templates);
  236. $radio = new RadioWidget($this->templates, $label);
  237. $data = [
  238. 'name' => 'Crayons[color]',
  239. 'options' => [
  240. ['value' => 'r', 'text' => 'Red', 'label' => ['style' => 'color:red']],
  241. ['value' => 'b', 'text' => 'Black', 'label' => ['data-test' => 'yes']],
  242. ],
  243. ];
  244. $result = $radio->render($data, $this->context);
  245. $expected = [
  246. ['label' => ['for' => 'crayons-color-r', 'style' => 'color:red']],
  247. ['input' => [
  248. 'type' => 'radio',
  249. 'name' => 'Crayons[color]',
  250. 'value' => 'r',
  251. 'id' => 'crayons-color-r',
  252. ]],
  253. 'Red',
  254. '/label',
  255. ['label' => ['for' => 'crayons-color-b', 'data-test' => 'yes']],
  256. ['input' => [
  257. 'type' => 'radio',
  258. 'name' => 'Crayons[color]',
  259. 'value' => 'b',
  260. 'id' => 'crayons-color-b',
  261. ]],
  262. 'Black',
  263. '/label',
  264. ];
  265. $this->assertHtml($expected, $result);
  266. }
  267. /**
  268. * Test that id suffixes are generated to not collide
  269. */
  270. public function testRenderIdSuffixGeneration(): void
  271. {
  272. $label = new NestingLabelWidget($this->templates);
  273. $radio = new RadioWidget($this->templates, $label);
  274. $data = [
  275. 'name' => 'Thing[value]',
  276. 'options' => ['a>b' => 'First', 'a<b' => 'Second'],
  277. ];
  278. $result = $radio->render($data, $this->context);
  279. $expected = [
  280. ['label' => ['for' => 'thing-value-a-b']],
  281. ['input' => [
  282. 'type' => 'radio',
  283. 'name' => 'Thing[value]',
  284. 'value' => 'a&gt;b',
  285. 'id' => 'thing-value-a-b',
  286. ]],
  287. 'First',
  288. '/label',
  289. ['label' => ['for' => 'thing-value-a-b1']],
  290. ['input' => [
  291. 'type' => 'radio',
  292. 'name' => 'Thing[value]',
  293. 'value' => 'a&lt;b',
  294. 'id' => 'thing-value-a-b1',
  295. ]],
  296. 'Second',
  297. '/label',
  298. ];
  299. $this->assertHtml($expected, $result);
  300. }
  301. /**
  302. * Test rendering checks the right option with booleanish values.
  303. */
  304. public function testRenderBooleanishValues(): void
  305. {
  306. $label = new NestingLabelWidget($this->templates);
  307. $radio = new RadioWidget($this->templates, $label);
  308. $data = [
  309. 'name' => 'Model[field]',
  310. 'options' => ['1' => 'Yes', '0' => 'No'],
  311. 'val' => '0',
  312. ];
  313. $result = $radio->render($data, $this->context);
  314. $expected = [
  315. ['label' => ['for' => 'model-field-1']],
  316. ['input' => ['type' => 'radio', 'name' => 'Model[field]', 'value' => '1', 'id' => 'model-field-1']],
  317. 'Yes',
  318. '/label',
  319. ['label' => ['for' => 'model-field-0']],
  320. ['input' => ['type' => 'radio', 'name' => 'Model[field]', 'value' => '0', 'id' => 'model-field-0', 'checked' => 'checked']],
  321. 'No',
  322. '/label',
  323. ];
  324. $this->assertHtml($expected, $result);
  325. $data['val'] = 0;
  326. $result = $radio->render($data, $this->context);
  327. $this->assertHtml($expected, $result);
  328. $data['val'] = false;
  329. $result = $radio->render($data, $this->context);
  330. $this->assertHtml($expected, $result);
  331. $expected = [
  332. ['label' => ['for' => 'model-field-1']],
  333. ['input' => ['type' => 'radio', 'name' => 'Model[field]', 'value' => '1', 'id' => 'model-field-1']],
  334. 'Yes',
  335. '/label',
  336. ['label' => ['for' => 'model-field-0']],
  337. ['input' => ['type' => 'radio', 'name' => 'Model[field]', 'value' => '0', 'id' => 'model-field-0']],
  338. 'No',
  339. '/label',
  340. ];
  341. $data['val'] = null;
  342. $result = $radio->render($data, $this->context);
  343. $this->assertHtml($expected, $result);
  344. $data['val'] = '';
  345. $result = $radio->render($data, $this->context);
  346. $this->assertHtml($expected, $result);
  347. $expected = [
  348. ['label' => ['for' => 'model-field-1']],
  349. ['input' => ['type' => 'radio', 'name' => 'Model[field]', 'value' => '1', 'id' => 'model-field-1', 'checked' => 'checked']],
  350. 'Yes',
  351. '/label',
  352. ['label' => ['for' => 'model-field-0']],
  353. ['input' => ['type' => 'radio', 'name' => 'Model[field]', 'value' => '0', 'id' => 'model-field-0']],
  354. 'No',
  355. '/label',
  356. ];
  357. $data['val'] = '1';
  358. $result = $radio->render($data, $this->context);
  359. $this->assertHtml($expected, $result);
  360. $data['val'] = 1;
  361. $result = $radio->render($data, $this->context);
  362. $this->assertHtml($expected, $result);
  363. $data['val'] = true;
  364. $result = $radio->render($data, $this->context);
  365. $this->assertHtml($expected, $result);
  366. }
  367. /**
  368. * Test that render() works with the required attribute.
  369. */
  370. public function testRenderRequiredAndFormAttribute(): void
  371. {
  372. $label = new NestingLabelWidget($this->templates);
  373. $radio = new RadioWidget($this->templates, $label);
  374. $data = [
  375. 'name' => 'published',
  376. 'options' => ['option A', 'option B'],
  377. 'required' => true,
  378. 'form' => 'my-form',
  379. ];
  380. $result = $radio->render($data, $this->context);
  381. $expected = [
  382. ['label' => ['for' => 'published-0']],
  383. ['input' => ['type' => 'radio', 'name' => 'published', 'value' => '0',
  384. 'id' => 'published-0', 'required' => 'required', 'form' => 'my-form']],
  385. 'option A',
  386. '/label',
  387. ['label' => ['for' => 'published-1']],
  388. ['input' => ['type' => 'radio', 'name' => 'published', 'value' => '1',
  389. 'id' => 'published-1', 'required' => 'required', 'form' => 'my-form']],
  390. 'option B',
  391. '/label',
  392. ];
  393. $this->assertHtml($expected, $result);
  394. }
  395. /**
  396. * Test rendering the empty option.
  397. */
  398. public function testRenderEmptyOption(): void
  399. {
  400. $label = new NestingLabelWidget($this->templates);
  401. $radio = new RadioWidget($this->templates, $label);
  402. $data = [
  403. 'name' => 'Crayons[color]',
  404. 'options' => ['r' => 'Red'],
  405. 'empty' => true,
  406. ];
  407. $result = $radio->render($data, $this->context);
  408. $expected = [
  409. ['label' => ['for' => 'crayons-color']],
  410. ['input' => [
  411. 'type' => 'radio',
  412. 'name' => 'Crayons[color]',
  413. 'value' => '',
  414. 'id' => 'crayons-color',
  415. ]],
  416. 'empty',
  417. '/label',
  418. ['label' => ['for' => 'crayons-color-r']],
  419. ['input' => [
  420. 'type' => 'radio',
  421. 'name' => 'Crayons[color]',
  422. 'value' => 'r',
  423. 'id' => 'crayons-color-r',
  424. ]],
  425. 'Red',
  426. '/label',
  427. ];
  428. $this->assertHtml($expected, $result);
  429. $data['empty'] = 'Choose one';
  430. $result = $radio->render($data, $this->context);
  431. $expected = [
  432. ['label' => ['for' => 'crayons-color']],
  433. ['input' => [
  434. 'type' => 'radio',
  435. 'name' => 'Crayons[color]',
  436. 'value' => '',
  437. 'id' => 'crayons-color',
  438. ]],
  439. 'Choose one',
  440. '/label',
  441. ['label' => ['for' => 'crayons-color-r']],
  442. ['input' => [
  443. 'type' => 'radio',
  444. 'name' => 'Crayons[color]',
  445. 'value' => 'r',
  446. 'id' => 'crayons-color-r',
  447. ]],
  448. 'Red',
  449. '/label',
  450. ];
  451. $this->assertHtml($expected, $result);
  452. }
  453. /**
  454. * Test rendering the input inside the label.
  455. */
  456. public function testRenderInputInsideLabel(): void
  457. {
  458. $this->templates->add([
  459. 'label' => '<label{{attrs}}>{{input}}{{text}}</label>',
  460. 'radioWrapper' => '{{label}}',
  461. ]);
  462. $label = new NestingLabelWidget($this->templates);
  463. $radio = new RadioWidget($this->templates, $label);
  464. $data = [
  465. 'name' => 'Crayons[color]',
  466. 'options' => ['r' => 'Red'],
  467. ];
  468. $result = $radio->render($data, $this->context);
  469. $expected = [
  470. ['label' => ['for' => 'crayons-color-r']],
  471. ['input' => [
  472. 'type' => 'radio',
  473. 'name' => 'Crayons[color]',
  474. 'value' => 'r',
  475. 'id' => 'crayons-color-r',
  476. ]],
  477. 'Red',
  478. '/label',
  479. ];
  480. $this->assertHtml($expected, $result);
  481. }
  482. /**
  483. * test render() and selected inputs.
  484. */
  485. public function testRenderSelected(): void
  486. {
  487. $label = new NestingLabelWidget($this->templates);
  488. $radio = new RadioWidget($this->templates, $label);
  489. $data = [
  490. 'name' => 'Versions[ver]',
  491. 'val' => '1',
  492. 'options' => [
  493. 1 => 'one',
  494. '1x' => 'one x',
  495. '2' => 'two',
  496. ],
  497. ];
  498. $result = $radio->render($data, $this->context);
  499. $expected = [
  500. ['label' => ['for' => 'versions-ver-1']],
  501. ['input' => [
  502. 'id' => 'versions-ver-1',
  503. 'name' => 'Versions[ver]',
  504. 'type' => 'radio',
  505. 'value' => '1',
  506. 'checked' => 'checked',
  507. ]],
  508. 'one',
  509. '/label',
  510. ['label' => ['for' => 'versions-ver-1x']],
  511. ['input' => [
  512. 'id' => 'versions-ver-1x',
  513. 'name' => 'Versions[ver]',
  514. 'type' => 'radio',
  515. 'value' => '1x',
  516. ]],
  517. 'one x',
  518. '/label',
  519. ['label' => ['for' => 'versions-ver-2']],
  520. ['input' => [
  521. 'id' => 'versions-ver-2',
  522. 'name' => 'Versions[ver]',
  523. 'type' => 'radio',
  524. 'value' => '2',
  525. ]],
  526. 'two',
  527. '/label',
  528. ];
  529. $this->assertHtml($expected, $result);
  530. }
  531. /**
  532. * Test rendering with disable inputs
  533. */
  534. public function testRenderDisabled(): void
  535. {
  536. $label = new NestingLabelWidget($this->templates);
  537. $radio = new RadioWidget($this->templates, $label);
  538. $data = [
  539. 'name' => 'Versions[ver]',
  540. 'options' => [
  541. 1 => 'one',
  542. '1x' => 'one x',
  543. '2' => 'two',
  544. ],
  545. 'disabled' => true,
  546. ];
  547. $result = $radio->render($data, $this->context);
  548. $expected = [
  549. ['label' => ['for' => 'versions-ver-1']],
  550. ['input' => [
  551. 'id' => 'versions-ver-1',
  552. 'name' => 'Versions[ver]',
  553. 'type' => 'radio',
  554. 'value' => '1',
  555. 'disabled' => 'disabled',
  556. ]],
  557. 'one',
  558. '/label',
  559. ['label' => ['for' => 'versions-ver-1x']],
  560. ['input' => [
  561. 'id' => 'versions-ver-1x',
  562. 'name' => 'Versions[ver]',
  563. 'type' => 'radio',
  564. 'value' => '1x',
  565. 'disabled' => 'disabled',
  566. ]],
  567. 'one x',
  568. '/label',
  569. ];
  570. $this->assertHtml($expected, $result);
  571. $data['disabled'] = 'a string';
  572. $result = $radio->render($data, $this->context);
  573. $this->assertHtml($expected, $result);
  574. $data['disabled'] = ['1'];
  575. $result = $radio->render($data, $this->context);
  576. $expected = [
  577. ['label' => ['for' => 'versions-ver-1']],
  578. ['input' => [
  579. 'id' => 'versions-ver-1',
  580. 'name' => 'Versions[ver]',
  581. 'type' => 'radio',
  582. 'value' => '1',
  583. 'disabled' => 'disabled',
  584. ]],
  585. 'one',
  586. '/label',
  587. ['label' => ['for' => 'versions-ver-1x']],
  588. ['input' => [
  589. 'id' => 'versions-ver-1x',
  590. 'name' => 'Versions[ver]',
  591. 'type' => 'radio',
  592. 'value' => '1x',
  593. ]],
  594. 'one x',
  595. '/label',
  596. ];
  597. $this->assertHtml($expected, $result);
  598. }
  599. /**
  600. * Test rendering with label options.
  601. */
  602. public function testRenderLabelOptions(): void
  603. {
  604. $label = new NestingLabelWidget($this->templates);
  605. $radio = new RadioWidget($this->templates, $label);
  606. $data = [
  607. 'name' => 'Versions[ver]',
  608. 'options' => [
  609. 1 => 'one',
  610. '1x' => 'one x',
  611. '2' => 'two',
  612. ],
  613. 'label' => false,
  614. ];
  615. $result = $radio->render($data, $this->context);
  616. $expected = [
  617. ['input' => [
  618. 'id' => 'versions-ver-1',
  619. 'name' => 'Versions[ver]',
  620. 'type' => 'radio',
  621. 'value' => '1',
  622. ]],
  623. ['input' => [
  624. 'id' => 'versions-ver-1x',
  625. 'name' => 'Versions[ver]',
  626. 'type' => 'radio',
  627. 'value' => '1x',
  628. ]],
  629. ];
  630. $this->assertHtml($expected, $result);
  631. $data = [
  632. 'name' => 'Versions[ver]',
  633. 'options' => [
  634. 1 => 'one',
  635. '1x' => 'one x',
  636. '2' => 'two',
  637. ],
  638. 'label' => [
  639. 'class' => 'my-class',
  640. ],
  641. ];
  642. $result = $radio->render($data, $this->context);
  643. $expected = [
  644. ['label' => ['class' => 'my-class', 'for' => 'versions-ver-1']],
  645. ['input' => [
  646. 'id' => 'versions-ver-1',
  647. 'name' => 'Versions[ver]',
  648. 'type' => 'radio',
  649. 'value' => '1',
  650. ]],
  651. 'one',
  652. '/label',
  653. ['label' => ['class' => 'my-class', 'for' => 'versions-ver-1x']],
  654. ['input' => [
  655. 'id' => 'versions-ver-1x',
  656. 'name' => 'Versions[ver]',
  657. 'type' => 'radio',
  658. 'value' => '1x',
  659. ]],
  660. 'one x',
  661. '/label',
  662. ];
  663. $this->assertHtml($expected, $result);
  664. }
  665. /**
  666. * Ensure that the input + label are composed with
  667. * a template.
  668. */
  669. public function testRenderContainerTemplate(): void
  670. {
  671. $this->templates->add([
  672. 'radioWrapper' => '<div class="radio">{{input}}{{label}}</div>',
  673. ]);
  674. $label = new NestingLabelWidget($this->templates);
  675. $radio = new RadioWidget($this->templates, $label);
  676. $data = [
  677. 'name' => 'Versions[ver]',
  678. 'options' => [
  679. 1 => 'one',
  680. '1x' => 'one x',
  681. '2' => 'two',
  682. ],
  683. ];
  684. $result = $radio->render($data, $this->context);
  685. $this->assertStringContainsString(
  686. '<div class="radio"><input type="radio"',
  687. $result
  688. );
  689. $this->assertStringContainsString(
  690. '</label></div>',
  691. $result
  692. );
  693. }
  694. /**
  695. * Ensure that template vars work.
  696. */
  697. public function testRenderTemplateVars(): void
  698. {
  699. $this->templates->add([
  700. 'radioWrapper' => '<div class="radio" data-var="{{wrapperVar}}">{{label}}</div>',
  701. 'radio' => '<input type="radio" data-i="{{inputVar}}" name="{{name}}" value="{{value}}"{{attrs}}>',
  702. 'nestingLabel' => '<label{{attrs}}>{{input}}{{text}} {{labelVar}} {{wrapperVar}}</label>',
  703. ]);
  704. $label = new NestingLabelWidget($this->templates);
  705. $radio = new RadioWidget($this->templates, $label);
  706. $data = [
  707. 'name' => 'Versions[ver]',
  708. 'options' => [
  709. ['value' => '1x', 'text' => 'one x', 'templateVars' => ['labelVar' => 'l-var', 'inputVar' => 'i-var']],
  710. '2' => 'two',
  711. ],
  712. 'templateVars' => [
  713. 'wrapperVar' => 'wrap-var',
  714. ],
  715. ];
  716. $result = $radio->render($data, $this->context);
  717. $this->assertStringContainsString('data-var="wrap-var"><label', $result);
  718. $this->assertStringContainsString('type="radio" data-i="i-var"', $result);
  719. $this->assertStringContainsString('one x l-var wrap-var</label>', $result);
  720. $this->assertStringContainsString('two wrap-var</label>', $result);
  721. }
  722. /**
  723. * testRenderCustomAttributes method
  724. *
  725. * Test render with custom attributes.
  726. */
  727. public function testRenderCustomAttributes(): void
  728. {
  729. $label = new NestingLabelWidget($this->templates);
  730. $radio = new RadioWidget($this->templates, $label);
  731. $result = $radio->render([
  732. 'name' => 'Model[field]',
  733. 'label' => null,
  734. 'options' => ['option A', 'option B'],
  735. 'class' => 'my-class',
  736. 'data-ref' => 'custom-attr',
  737. ], $this->context);
  738. $expected = [
  739. ['label' => ['for' => 'model-field-0']],
  740. [
  741. 'input' => [
  742. 'type' => 'radio',
  743. 'name' => 'Model[field]',
  744. 'value' => '0',
  745. 'id' => 'model-field-0',
  746. 'class' => 'my-class',
  747. 'data-ref' => 'custom-attr',
  748. ],
  749. ],
  750. 'option A',
  751. '/label',
  752. ['label' => ['for' => 'model-field-1']],
  753. [
  754. 'input' => [
  755. 'type' => 'radio',
  756. 'name' => 'Model[field]',
  757. 'value' => '1',
  758. 'id' => 'model-field-1',
  759. 'class' => 'my-class',
  760. 'data-ref' => 'custom-attr',
  761. ],
  762. ],
  763. 'option B',
  764. '/label',
  765. ];
  766. $this->assertHtml($expected, $result);
  767. }
  768. /**
  769. * testRenderExplicitId method
  770. *
  771. * Test that the id passed is actually used
  772. * Issue: https://github.com/cakephp/cakephp/issues/13342
  773. */
  774. public function testRenderExplicitId(): void
  775. {
  776. $label = new NestingLabelWidget($this->templates);
  777. $input = new RadioWidget($this->templates, $label);
  778. $data = [
  779. 'name' => 'field',
  780. 'options' => ['value1', 'value2', -1 => 'negative'],
  781. 'id' => 'alternative-id',
  782. 'idPrefix' => 'willBeIgnored',
  783. ];
  784. $result = $input->render($data, $this->context);
  785. $expected = [
  786. [
  787. 'label' => ['for' => 'alternative-id-0'],
  788. 'input' => ['type' => 'radio', 'name' => 'field', 'value' => '0', 'id' => 'alternative-id-0'],
  789. ],
  790. 'value1',
  791. '/label',
  792. [
  793. 'label' => ['for' => 'alternative-id-1'],
  794. 'input' => ['type' => 'radio', 'name' => 'field', 'value' => '1', 'id' => 'alternative-id-1'],
  795. ],
  796. 'value2',
  797. '/label',
  798. [
  799. 'label' => ['for' => 'alternative-id--1'],
  800. 'input' => ['type' => 'radio', 'name' => 'field', 'value' => '-1', 'id' => 'alternative-id--1'],
  801. ],
  802. 'negative',
  803. '/label',
  804. ];
  805. $this->assertHtml($expected, $result);
  806. $data = [
  807. 'name' => 'field',
  808. 'options' => ['value1', 'value2'],
  809. 'idPrefix' => 'formprefix',
  810. ];
  811. $result = $input->render($data, $this->context);
  812. $expected = [
  813. [
  814. 'label' => ['for' => 'formprefix-field-0'],
  815. 'input' => ['type' => 'radio', 'name' => 'field', 'value' => '0', 'id' => 'formprefix-field-0'],
  816. ],
  817. 'value1',
  818. '/label',
  819. [
  820. 'label' => ['for' => 'formprefix-field-1'],
  821. 'input' => ['type' => 'radio', 'name' => 'field', 'value' => '1', 'id' => 'formprefix-field-1'],
  822. ],
  823. 'value2',
  824. '/label',
  825. ];
  826. $this->assertHtml($expected, $result);
  827. }
  828. /**
  829. * testRenderSelectedClass method
  830. *
  831. * Test that the custom selected class is passed to label
  832. * Issue: https://github.com/cakephp/cakephp/issues/11249
  833. */
  834. public function testRenderSelectedClass(): void
  835. {
  836. $this->templates->add(['selectedClass' => 'active']);
  837. $label = new NestingLabelWidget($this->templates);
  838. $input = new RadioWidget($this->templates, $label);
  839. $data = [
  840. 'name' => 'field',
  841. 'options' => ['value1' => 'title1'],
  842. 'val' => 'value1',
  843. 'label' => ['title' => 'my label'],
  844. ];
  845. $result = $input->render($data, $this->context);
  846. $expected = [
  847. ['label' => [
  848. 'title' => 'my label',
  849. 'class' => 'active',
  850. 'for' => 'field-value1',
  851. ]],
  852. ];
  853. $this->assertHtml($expected, $result);
  854. }
  855. }