BreadcrumbsHelperTest.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  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.3.6
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\Test\TestCase\View\Helper;
  17. use Cake\Routing\Router;
  18. use Cake\TestSuite\TestCase;
  19. use Cake\View\Helper\BreadcrumbsHelper;
  20. use Cake\View\View;
  21. use LogicException;
  22. class BreadcrumbsHelperTest extends TestCase
  23. {
  24. /**
  25. * Instance of the BreadcrumbsHelper
  26. *
  27. * @var BreadcrumbsHelper
  28. */
  29. protected $breadcrumbs;
  30. /**
  31. * setUp method
  32. */
  33. public function setUp(): void
  34. {
  35. parent::setUp();
  36. $view = new View();
  37. $this->breadcrumbs = new BreadcrumbsHelper($view);
  38. Router::reload();
  39. Router::createRouteBuilder('/')->fallbacks();
  40. }
  41. /**
  42. * Test adding crumbs to the trail using add()
  43. */
  44. public function testAdd(): void
  45. {
  46. $this->breadcrumbs
  47. ->add('Home', '/', ['class' => 'first'])
  48. ->add('Some text', ['controller' => 'Some', 'action' => 'text']);
  49. $result = $this->breadcrumbs->getCrumbs();
  50. $expected = [
  51. [
  52. 'title' => 'Home',
  53. 'url' => '/',
  54. 'options' => [
  55. 'class' => 'first',
  56. ],
  57. ],
  58. [
  59. 'title' => 'Some text',
  60. 'url' => [
  61. 'controller' => 'Some',
  62. 'action' => 'text',
  63. ],
  64. 'options' => [],
  65. ],
  66. ];
  67. $this->assertEquals($expected, $result);
  68. }
  69. /**
  70. * Test adding multiple crumbs at once to the trail using add()
  71. */
  72. public function testAddMultiple(): void
  73. {
  74. $this->breadcrumbs
  75. ->add([
  76. [
  77. 'title' => 'Home',
  78. 'url' => '/',
  79. 'options' => ['class' => 'first'],
  80. ],
  81. [
  82. 'title' => 'Some text',
  83. 'url' => ['controller' => 'Some', 'action' => 'text'],
  84. ],
  85. [
  86. 'title' => 'Final',
  87. ],
  88. ]);
  89. $result = $this->breadcrumbs->getCrumbs();
  90. $expected = [
  91. [
  92. 'title' => 'Home',
  93. 'url' => '/',
  94. 'options' => [
  95. 'class' => 'first',
  96. ],
  97. ],
  98. [
  99. 'title' => 'Some text',
  100. 'url' => [
  101. 'controller' => 'Some',
  102. 'action' => 'text',
  103. ],
  104. 'options' => [],
  105. ],
  106. [
  107. 'title' => 'Final',
  108. 'url' => null,
  109. 'options' => [],
  110. ],
  111. ];
  112. $this->assertEquals($expected, $result);
  113. }
  114. /**
  115. * Test adding crumbs to the trail using prepend()
  116. */
  117. public function testPrepend(): void
  118. {
  119. $this->breadcrumbs
  120. ->add('Home', '/', ['class' => 'first'])
  121. ->prepend('Some text', ['controller' => 'Some', 'action' => 'text'])
  122. ->prepend('The root', '/root', ['data-name' => 'some-name']);
  123. $result = $this->breadcrumbs->getCrumbs();
  124. $expected = [
  125. [
  126. 'title' => 'The root',
  127. 'url' => '/root',
  128. 'options' => ['data-name' => 'some-name'],
  129. ],
  130. [
  131. 'title' => 'Some text',
  132. 'url' => [
  133. 'controller' => 'Some',
  134. 'action' => 'text',
  135. ],
  136. 'options' => [],
  137. ],
  138. [
  139. 'title' => 'Home',
  140. 'url' => '/',
  141. 'options' => [
  142. 'class' => 'first',
  143. ],
  144. ],
  145. ];
  146. $this->assertEquals($expected, $result);
  147. }
  148. /**
  149. * Test adding crumbs to the trail using prepend()
  150. */
  151. public function testPrependMultiple(): void
  152. {
  153. $this->breadcrumbs
  154. ->add('Home', '/', ['class' => 'first'])
  155. ->prepend([
  156. ['title' => 'Some text', 'url' => ['controller' => 'Some', 'action' => 'text']],
  157. ['title' => 'The root', 'url' => '/root', 'options' => ['data-name' => 'some-name']],
  158. ]);
  159. $result = $this->breadcrumbs->getCrumbs();
  160. $expected = [
  161. [
  162. 'title' => 'Some text',
  163. 'url' => [
  164. 'controller' => 'Some',
  165. 'action' => 'text',
  166. ],
  167. 'options' => [],
  168. ],
  169. [
  170. 'title' => 'The root',
  171. 'url' => '/root',
  172. 'options' => ['data-name' => 'some-name'],
  173. ],
  174. [
  175. 'title' => 'Home',
  176. 'url' => '/',
  177. 'options' => [
  178. 'class' => 'first',
  179. ],
  180. ],
  181. ];
  182. $this->assertEquals($expected, $result);
  183. }
  184. /**
  185. * Test ability to empty crumbs list.
  186. */
  187. public function testReset(): void
  188. {
  189. $this->breadcrumbs->add('Home', '/');
  190. $this->breadcrumbs->add('Products', '/products');
  191. $crumbs = $this->breadcrumbs->getCrumbs();
  192. $this->assertSame(count($crumbs), 2);
  193. $this->breadcrumbs->reset();
  194. $actual = $this->breadcrumbs->getCrumbs();
  195. $this->assertEquals($actual, []);
  196. }
  197. /**
  198. * Test adding crumbs to a specific index
  199. */
  200. public function testInsertAt(): void
  201. {
  202. $this->breadcrumbs
  203. ->add('Home', '/', ['class' => 'first'])
  204. ->prepend('Some text', ['controller' => 'Some', 'action' => 'text'])
  205. ->insertAt(1, 'Insert At', ['controller' => 'Insert', 'action' => 'at'])
  206. ->insertAt(1, 'Insert At Again', ['controller' => 'Insert', 'action' => 'at_again']);
  207. $result = $this->breadcrumbs->getCrumbs();
  208. $expected = [
  209. [
  210. 'title' => 'Some text',
  211. 'url' => [
  212. 'controller' => 'Some',
  213. 'action' => 'text',
  214. ],
  215. 'options' => [],
  216. ],
  217. [
  218. 'title' => 'Insert At Again',
  219. 'url' => [
  220. 'controller' => 'Insert',
  221. 'action' => 'at_again',
  222. ],
  223. 'options' => [],
  224. ],
  225. [
  226. 'title' => 'Insert At',
  227. 'url' => [
  228. 'controller' => 'Insert',
  229. 'action' => 'at',
  230. ],
  231. 'options' => [],
  232. ],
  233. [
  234. 'title' => 'Home',
  235. 'url' => '/',
  236. 'options' => [
  237. 'class' => 'first',
  238. ],
  239. ],
  240. ];
  241. $this->assertEquals($expected, $result);
  242. }
  243. /**
  244. * Test adding crumbs to a specific index
  245. */
  246. public function testInsertAtIndexOutOfBounds(): void
  247. {
  248. $this->expectException(LogicException::class);
  249. $this->breadcrumbs
  250. ->add('Home', '/', ['class' => 'first'])
  251. ->insertAt(2, 'Insert At Again', ['controller' => 'Insert', 'action' => 'at_again']);
  252. }
  253. /**
  254. * Test adding crumbs before a specific one
  255. */
  256. public function testInsertBefore(): void
  257. {
  258. $this->breadcrumbs
  259. ->add('Home', '/', ['class' => 'first'])
  260. ->prepend('Some text', ['controller' => 'Some', 'action' => 'text'])
  261. ->prepend('The root', '/root', ['data-name' => 'some-name'])
  262. ->insertBefore('The root', 'The super root');
  263. $result = $this->breadcrumbs->getCrumbs();
  264. $expected = [
  265. [
  266. 'title' => 'The super root',
  267. 'url' => null,
  268. 'options' => [],
  269. ],
  270. [
  271. 'title' => 'The root',
  272. 'url' => '/root',
  273. 'options' => ['data-name' => 'some-name'],
  274. ],
  275. [
  276. 'title' => 'Some text',
  277. 'url' => [
  278. 'controller' => 'Some',
  279. 'action' => 'text',
  280. ],
  281. 'options' => [],
  282. ],
  283. [
  284. 'title' => 'Home',
  285. 'url' => '/',
  286. 'options' => [
  287. 'class' => 'first',
  288. ],
  289. ],
  290. ];
  291. $this->assertEquals($expected, $result);
  292. }
  293. /**
  294. * Test adding crumbs after a specific one
  295. */
  296. public function testInsertAfter(): void
  297. {
  298. $this->breadcrumbs
  299. ->add('Home', '/', ['class' => 'first'])
  300. ->prepend('Some text', ['controller' => 'Some', 'action' => 'text'])
  301. ->prepend('The root', '/root', ['data-name' => 'some-name'])
  302. ->insertAfter('The root', 'The less super root');
  303. $result = $this->breadcrumbs->getCrumbs();
  304. $expected = [
  305. [
  306. 'title' => 'The root',
  307. 'url' => '/root',
  308. 'options' => ['data-name' => 'some-name'],
  309. ],
  310. [
  311. 'title' => 'The less super root',
  312. 'url' => null,
  313. 'options' => [],
  314. ],
  315. [
  316. 'title' => 'Some text',
  317. 'url' => [
  318. 'controller' => 'Some',
  319. 'action' => 'text',
  320. ],
  321. 'options' => [],
  322. ],
  323. [
  324. 'title' => 'Home',
  325. 'url' => '/',
  326. 'options' => [
  327. 'class' => 'first',
  328. ],
  329. ],
  330. ];
  331. $this->assertEquals($expected, $result);
  332. }
  333. /**
  334. * Test adding crumbs after a specific one
  335. */
  336. public function testInsertAfterLastItem(): void
  337. {
  338. $this->breadcrumbs
  339. ->add('Home', '/')
  340. ->insertAfter('Home', 'Below Home', '/below', ['class' => 'second']);
  341. $result = $this->breadcrumbs->getCrumbs();
  342. $expected = [
  343. [
  344. 'title' => 'Home',
  345. 'url' => '/',
  346. 'options' => [],
  347. ],
  348. [
  349. 'title' => 'Below Home',
  350. 'url' => '/below',
  351. 'options' => [
  352. 'class' => 'second',
  353. ],
  354. ],
  355. ];
  356. $this->assertEquals($expected, $result);
  357. }
  358. /**
  359. * Tests the render method
  360. */
  361. public function testRender(): void
  362. {
  363. $this->assertSame('', $this->breadcrumbs->render());
  364. $this->breadcrumbs
  365. ->add('Home', '/', ['class' => 'first', 'innerAttrs' => ['data-foo' => 'bar']])
  366. ->add('Some text', ['controller' => 'TestsApps', 'action' => 'someMethod'])
  367. ->add('Final crumb', null, ['class' => 'final', 'innerAttrs' => ['class' => 'final-link']]);
  368. $result = $this->breadcrumbs->render(
  369. ['data-stuff' => 'foo and bar'],
  370. ['separator' => '<i class="fa fa-angle-right"></i>', 'class' => 'separator']
  371. );
  372. $expected = [
  373. ['ul' => ['data-stuff' => 'foo and bar']],
  374. ['li' => ['class' => 'first']],
  375. ['a' => ['href' => '/', 'data-foo' => 'bar']],
  376. 'Home',
  377. '/a',
  378. '/li',
  379. ['li' => ['class' => 'separator']],
  380. ['span' => []],
  381. ['i' => ['class' => 'fa fa-angle-right']],
  382. '/i',
  383. '/span',
  384. '/li',
  385. ['li' => []],
  386. ['a' => ['href' => '/TestsApps/someMethod']],
  387. 'Some text',
  388. '/a',
  389. '/li',
  390. ['li' => ['class' => 'separator']],
  391. ['span' => []],
  392. ['i' => ['class' => 'fa fa-angle-right']],
  393. '/i',
  394. '/span',
  395. '/li',
  396. ['li' => ['class' => 'final']],
  397. ['span' => ['class' => 'final-link']],
  398. 'Final crumb',
  399. '/span',
  400. '/li',
  401. '/ul',
  402. ];
  403. $this->assertHtml($expected, $result);
  404. }
  405. /**
  406. * Tests the render method with custom templates
  407. */
  408. public function testRenderCustomTemplate(): void
  409. {
  410. $this->breadcrumbs = new BreadcrumbsHelper(new View(), [
  411. 'templates' => [
  412. 'wrapper' => '<ol itemtype="http://schema.org/BreadcrumbList"{{attrs}}>{{content}}</ol>',
  413. 'item' => '<li itemprop="itemListElement" itemtype="http://schema.org/ListItem"{{attrs}}><a itemtype="http://schema.org/Thing" itemprop="item" href="{{url}}"{{innerAttrs}}><span itemprop="name">{{title}}</span></a></li>',
  414. 'itemWithoutLink' => '<li itemprop="itemListElement" itemtype="http://schema.org/ListItem"{{attrs}}><span itemprop="name"{{innerAttrs}}>{{title}}</span></li>',
  415. ],
  416. ]);
  417. $this->breadcrumbs
  418. ->add('Home', '/', ['class' => 'first', 'innerAttrs' => ['data-foo' => 'bar']])
  419. ->add('Final crumb', null, ['class' => 'final', 'innerAttrs' => ['class' => 'final-link']]);
  420. $result = $this->breadcrumbs->render(
  421. ['data-stuff' => 'foo and bar'],
  422. ['separator' => ' > ', 'class' => 'separator']
  423. );
  424. $expected = [
  425. ['ol' => ['itemtype' => 'http://schema.org/BreadcrumbList', 'data-stuff' => 'foo and bar']],
  426. ['li' => ['itemprop' => 'itemListElement', 'itemtype' => 'http://schema.org/ListItem', 'class' => 'first']],
  427. ['a' => ['itemtype' => 'http://schema.org/Thing', 'itemprop' => 'item', 'href' => '/', 'data-foo' => 'bar']],
  428. ['span' => ['itemprop' => 'name']],
  429. 'Home',
  430. '/span',
  431. '/a',
  432. '/li',
  433. ['li' => ['itemprop' => 'itemListElement', 'itemtype' => 'http://schema.org/ListItem', 'class' => 'final']],
  434. ['span' => ['itemprop' => 'name', 'class' => 'final-link']],
  435. 'Final crumb',
  436. '/span',
  437. '/li',
  438. '/ol',
  439. ];
  440. $this->assertHtml($expected, $result, true);
  441. }
  442. /**
  443. * Tests the render method with template vars
  444. */
  445. public function testRenderCustomTemplateTemplateVars(): void
  446. {
  447. $this->breadcrumbs = new BreadcrumbsHelper(new View(), [
  448. 'templates' => [
  449. 'wrapper' => '{{thing}}<ol itemtype="http://schema.org/BreadcrumbList"{{attrs}}>{{content}}</ol>',
  450. 'item' => '<li itemprop="itemListElement" itemtype="http://schema.org/ListItem"{{attrs}}><a itemtype="http://schema.org/Thing" itemprop="item" href="{{url}}"{{innerAttrs}}><span itemprop="name">{{title}}</span></a>{{foo}}</li>',
  451. 'itemWithoutLink' => '<li itemprop="itemListElement" itemtype="http://schema.org/ListItem"{{attrs}}><span itemprop="name"{{innerAttrs}}>{{title}}</span>{{barbaz}}</li>',
  452. ],
  453. ]);
  454. $this->breadcrumbs
  455. ->add('Home', '/', ['class' => 'first', 'innerAttrs' => ['data-foo' => 'bar'], 'templateVars' => ['foo' => 'barbaz']])
  456. ->add('Final crumb', null, ['class' => 'final', 'innerAttrs' => ['class' => 'final-link'], 'templateVars' => ['barbaz' => 'foo']]);
  457. $result = $this->breadcrumbs->render(
  458. ['data-stuff' => 'foo and bar', 'templateVars' => ['thing' => 'somestuff']],
  459. ['separator' => ' > ', 'class' => 'separator']
  460. );
  461. $expected = [
  462. 'somestuff',
  463. ['ol' => ['itemtype' => 'http://schema.org/BreadcrumbList', 'data-stuff' => 'foo and bar']],
  464. ['li' => ['itemprop' => 'itemListElement', 'itemtype' => 'http://schema.org/ListItem', 'class' => 'first']],
  465. ['a' => ['itemtype' => 'http://schema.org/Thing', 'itemprop' => 'item', 'href' => '/', 'data-foo' => 'bar']],
  466. ['span' => ['itemprop' => 'name']],
  467. 'Home',
  468. '/span',
  469. '/a',
  470. 'barbaz',
  471. '/li',
  472. ['li' => ['itemprop' => 'itemListElement', 'itemtype' => 'http://schema.org/ListItem', 'class' => 'final']],
  473. ['span' => ['itemprop' => 'name', 'class' => 'final-link']],
  474. 'Final crumb',
  475. '/span',
  476. 'foo',
  477. '/li',
  478. '/ol',
  479. ];
  480. $this->assertHtml($expected, $result, true);
  481. }
  482. }