2 namespace TYPO3\CMS\Frontend\Tests\Unit\ContentObject
;
5 * This file is part of the TYPO3 CMS project.
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use TYPO3\CMS\Core\Page\PageRenderer
;
18 use TYPO3\CMS\Core\TypoScript\TypoScriptService
;
19 use TYPO3\CMS\Core\Utility\GeneralUtility
;
20 use TYPO3\CMS\Extbase\Mvc\Request
;
21 use TYPO3\CMS\Fluid\View\StandaloneView
;
22 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
;
23 use TYPO3\CMS\Frontend\ContentObject\FluidTemplateContentObject
;
24 use TYPO3Fluid\Fluid\View\TemplateView
;
29 class FluidTemplateContentObjectTest
extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
32 * @var array A backup of registered singleton instances
34 protected $singletonInstances = [];
37 * @var FluidTemplateContentObject|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface
39 protected $subject = null;
42 * @var ContentObjectRenderer|\PHPUnit_Framework_MockObject_MockObject
44 protected $contentObjectRenderer = null;
47 * @var StandaloneView|\PHPUnit_Framework_MockObject_MockObject
49 protected $standaloneView = null;
52 * @var Request|\PHPUnit_Framework_MockObject_MockObject
54 protected $request = null;
59 protected function setUp()
61 $this->singletonInstances
= GeneralUtility
::getSingletonInstances();
62 $this->contentObjectRenderer
= $this->getMockBuilder(
63 \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
::class
65 $this->subject
= $this->getAccessibleMock(
66 \TYPO3\CMS\Frontend\ContentObject\FluidTemplateContentObject
::class,
67 ['initializeStandaloneViewInstance'],
68 [$this->contentObjectRenderer
]
70 /** @var $tsfe \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController */
71 $tsfe = $this->createMock(\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
::class);
72 $tsfe->tmpl
= $this->getMockBuilder(\TYPO3\CMS\Core\TypoScript\TemplateService
::class)->getMock();
73 $GLOBALS['TSFE'] = $tsfe;
79 protected function tearDown()
81 GeneralUtility
::resetSingletonInstances($this->singletonInstances
);
86 * Add a mock standalone view to subject
88 protected function addMockViewToSubject()
90 $this->standaloneView
= $this->createMock(\TYPO3\CMS\Fluid\View\StandaloneView
::class);
91 $this->request
= $this->getMockBuilder(\TYPO3\CMS\Extbase\Mvc\Request
::class)->getMock();
93 ->expects($this->any())
94 ->method('getRequest')
95 ->will($this->returnValue($this->request
));
96 $this->subject
->_set('view', $this->standaloneView
);
102 public function constructSetsContentObjectRenderer()
104 $this->assertSame($this->contentObjectRenderer
, $this->subject
->getContentObjectRenderer());
110 public function renderCallsInitializeStandaloneViewInstance()
112 $this->addMockViewToSubject();
114 ->expects($this->once())
115 ->method('initializeStandaloneViewInstance');
116 $this->subject
->render([]);
122 public function renderCallsTemplateServiceGetFileNameForGivenTemplateFile()
124 $this->addMockViewToSubject();
125 /** @var $templateService \PHPUnit_Framework_MockObject_MockObject */
126 $templateService = $GLOBALS['TSFE']->tmpl
;
128 ->expects($this->any())
129 ->method('getFileName')
131 $this->subject
->render(['file' => 'foo']);
137 public function renderCallsStandardWrapForGivenTemplateFileWithStandardWrap()
139 $this->addMockViewToSubject();
140 $this->contentObjectRenderer
141 ->expects($this->any())
143 ->with('foo', ['bar' => 'baz']);
144 $this->subject
->render(['file' => 'foo', 'file.' => ['bar' => 'baz']]);
150 public function renderCallsStandardWrapForGivenTemplateRootPathsWithStandardWrap()
152 $this->addMockViewToSubject();
153 $this->contentObjectRenderer
154 ->expects($this->at(0))
156 ->with('dummyPath', ['wrap' => '|5/']);
157 $this->contentObjectRenderer
158 ->expects($this->at(1))
160 ->with('', ['field' => 'someField']);
161 $this->subject
->render(
163 'templateName' => 'foobar',
164 'templateRootPaths.' => [
171 'field' => 'someField',
181 public function renderSetsTemplateFileInView()
183 $this->addMockViewToSubject();
184 /** @var $templateService \PHPUnit_Framework_MockObject_MockObject */
185 $templateService = $GLOBALS['TSFE']->tmpl
;
187 ->expects($this->any())
188 ->method('getFileName')
190 ->will($this->returnValue('bar'));
191 $this->standaloneView
192 ->expects($this->any())
193 ->method('setTemplatePathAndFilename')
194 ->with(PATH_site
. 'bar');
195 $this->subject
->render(['file' => 'foo']);
201 public function renderSetsTemplateFileByTemplateInView()
203 $this->addMockViewToSubject();
205 $this->contentObjectRenderer
206 ->expects($this->any())
207 ->method('cObjGetSingle')
208 ->with('FILE', ['file' => PATH_site
. 'foo/bar.html'])
209 ->will($this->returnValue('baz'));
211 $this->standaloneView
212 ->expects($this->any())
213 ->method('setTemplateSource')
216 $this->subject
->render([
217 'template' => 'FILE',
219 'file' => PATH_site
. 'foo/bar.html'
227 public function renderSetsTemplateFileByTemplateNameInView()
229 $this->addMockViewToSubject();
231 $this->standaloneView
232 ->expects($this->any())
233 ->method('getFormat')
234 ->will($this->returnValue('html'));
235 $this->standaloneView
236 ->expects($this->once())
237 ->method('setTemplate')
240 $this->subject
->render(
242 'templateName' => 'foo',
243 'templateRootPaths.' => [
253 public function renderSetsTemplateFileByTemplateNameStdWrapInView()
255 $this->addMockViewToSubject();
257 $this->contentObjectRenderer
258 ->expects($this->once())
260 ->with('TEXT', ['value' => 'bar'])
261 ->will($this->returnValue('bar'));
262 $this->standaloneView
263 ->expects($this->any())
264 ->method('getFormat')
265 ->will($this->returnValue('html'));
266 $this->standaloneView
267 ->expects($this->once())
268 ->method('setTemplate')
271 $this->subject
->render(
273 'templateName' => 'TEXT',
274 'templateName.' => ['value' => 'bar'],
275 'templateRootPaths.' => [
285 public function renderSetsLayoutRootPathInView()
287 $this->addMockViewToSubject();
288 $this->standaloneView
289 ->expects($this->once())
290 ->method('setLayoutRootPaths')
291 ->with([PATH_site
. 'foo/bar.html']);
292 $this->subject
->render(['layoutRootPath' => 'foo/bar.html']);
298 public function renderCallsStandardWrapForLayoutRootPath()
300 $this->addMockViewToSubject();
301 $this->contentObjectRenderer
302 ->expects($this->once())
304 ->with('foo', ['bar' => 'baz']);
305 $this->subject
->render(['layoutRootPath' => 'foo', 'layoutRootPath.' => ['bar' => 'baz']]);
311 public function layoutRootPathsHasStdWrapSupport()
313 $this->addMockViewToSubject();
314 $this->contentObjectRenderer
315 ->expects($this->at(0))
317 ->with('FILE', ['file' => 'foo/bar.html']);
318 $this->subject
->render(
320 'layoutRootPaths.' => [
323 'file' => 'foo/bar.html',
325 20 => 'foo/bar2.html',
334 public function fallbacksForLayoutRootPathAreSet()
336 $this->addMockViewToSubject();
337 $this->standaloneView
338 ->expects($this->once())
339 ->method('setLayoutRootPaths')
340 ->with([10 => PATH_site
. 'foo/bar.html', 20 => PATH_site
. 'foo/bar2.html']);
341 $this->subject
->render(['layoutRootPaths.' => [10 => 'foo/bar.html', 20 => 'foo/bar2.html']]);
347 public function fallbacksForLayoutRootPathAreAppendedToLayoutRootPath()
349 $this->addMockViewToSubject();
350 $this->standaloneView
351 ->expects($this->once())
352 ->method('setLayoutRootPaths')
353 ->with([0 => PATH_site
. 'foo/main.html', 10 => PATH_site
. 'foo/bar.html', 20 => PATH_site
. 'foo/bar2.html']);
354 $this->subject
->render(['layoutRootPath' => 'foo/main.html', 'layoutRootPaths.' => [10 => 'foo/bar.html', 20 => 'foo/bar2.html']]);
360 public function renderSetsPartialRootPathInView()
362 $this->addMockViewToSubject();
363 $this->standaloneView
364 ->expects($this->once())
365 ->method('setPartialRootPaths')
366 ->with([PATH_site
. 'foo/bar.html']);
367 $this->subject
->render(['partialRootPath' => 'foo/bar.html']);
373 public function partialRootPathsHasStdWrapSupport()
375 $this->addMockViewToSubject();
376 $this->contentObjectRenderer
377 ->expects($this->at(0))
379 ->with('FILE', ['file' => 'foo/bar.html']);
380 $this->subject
->render(
382 'partialRootPaths.' => [
385 'file' => 'foo/bar.html',
387 20 => 'foo/bar2.html',
396 public function renderCallsStandardWrapForPartialRootPath()
398 $this->addMockViewToSubject();
399 $this->contentObjectRenderer
400 ->expects($this->once())
402 ->with('foo', ['bar' => 'baz']);
403 $this->subject
->render(['partialRootPath' => 'foo', 'partialRootPath.' => ['bar' => 'baz']]);
409 public function fallbacksForPartialRootPathAreSet()
411 $this->addMockViewToSubject();
412 $this->standaloneView
413 ->expects($this->once())
414 ->method('setPartialRootPaths')
415 ->with([10 => PATH_site
. 'foo', 20 => PATH_site
. 'bar']);
416 $this->subject
->render(['partialRootPaths.' => [10 => 'foo', 20 => 'bar']]);
422 public function fallbacksForPartialRootPathAreAppendedToPartialRootPath()
424 $this->addMockViewToSubject();
425 $this->standaloneView
426 ->expects($this->once())
427 ->method('setPartialRootPaths')
428 ->with([0 => PATH_site
. 'main', 10 => PATH_site
. 'foo', 20 => PATH_site
. 'bar']);
429 $this->subject
->render(['partialRootPath' => 'main', 'partialRootPaths.' => [10 => 'foo', 20 => 'bar']]);
435 public function renderSetsFormatInView()
437 $this->addMockViewToSubject();
438 $this->standaloneView
439 ->expects($this->once())
440 ->method('setFormat')
442 $this->subject
->render(['format' => 'xml']);
448 public function renderCallsStandardWrapForFormat()
450 $this->addMockViewToSubject();
451 $this->contentObjectRenderer
452 ->expects($this->once())
454 ->with('foo', ['bar' => 'baz']);
455 $this->subject
->render(['format' => 'foo', 'format.' => ['bar' => 'baz']]);
461 public function renderSetsExtbasePluginNameInRequest()
463 $this->addMockViewToSubject();
465 ->expects($this->once())
466 ->method('setPluginName')
470 'pluginName' => 'foo',
473 $this->subject
->render($configuration);
479 public function renderCallsStandardWrapForExtbasePluginName()
481 $this->addMockViewToSubject();
482 $this->contentObjectRenderer
483 ->expects($this->once())
485 ->with('foo', ['bar' => 'baz']);
488 'pluginName' => 'foo',
494 $this->subject
->render($configuration);
500 public function renderSetsExtbaseControllerExtensionNameInRequest()
502 $this->addMockViewToSubject();
504 ->expects($this->once())
505 ->method('setControllerExtensionName')
509 'controllerExtensionName' => 'foo',
512 $this->subject
->render($configuration);
518 public function renderCallsStandardWrapForExtbaseControllerExtensionName()
520 $this->addMockViewToSubject();
521 $this->contentObjectRenderer
522 ->expects($this->once())
524 ->with('foo', ['bar' => 'baz']);
527 'controllerExtensionName' => 'foo',
528 'controllerExtensionName.' => [
533 $this->subject
->render($configuration);
539 public function renderSetsExtbaseControllerNameInRequest()
541 $this->addMockViewToSubject();
543 ->expects($this->once())
544 ->method('setControllerName')
548 'controllerName' => 'foo',
551 $this->subject
->render($configuration);
557 public function renderCallsStandardWrapForExtbaseControllerName()
559 $this->addMockViewToSubject();
560 $this->contentObjectRenderer
561 ->expects($this->once())
563 ->with('foo', ['bar' => 'baz']);
566 'controllerName' => 'foo',
567 'controllerName.' => [
572 $this->subject
->render($configuration);
578 public function renderSetsExtbaseControllerActionNameInRequest()
580 $this->addMockViewToSubject();
582 ->expects($this->once())
583 ->method('setControllerActionName')
587 'controllerActionName' => 'foo',
590 $this->subject
->render($configuration);
596 public function renderCallsStandardWrapForExtbaseControllerActionName()
598 $this->addMockViewToSubject();
599 $this->contentObjectRenderer
600 ->expects($this->once())
602 ->with('foo', ['bar' => 'baz']);
605 'controllerActionName' => 'foo',
606 'controllerActionName.' => [
611 $this->subject
->render($configuration);
617 public function renderAssignsSettingsArrayToView()
619 $this->addMockViewToSubject();
630 $expectedSettingsToBeSet = [
637 /** @var TypoScriptService|\PHPUnit_Framework_MockObject_MockObject $typoScriptServiceMock */
638 $typoScriptServiceMock = $this->getMockBuilder(TypoScriptService
::class)->getMock();
639 $typoScriptServiceMock
640 ->expects($this->once())
641 ->method('convertTypoScriptArrayToPlainArray')
642 ->with($configuration['settings.'])
643 ->will($this->returnValue($expectedSettingsToBeSet));
644 GeneralUtility
::addInstance(TypoScriptService
::class, $typoScriptServiceMock);
646 $this->standaloneView
647 ->expects($this->at(1))
649 ->with('settings', $expectedSettingsToBeSet);
651 $this->subject
->render($configuration);
657 public function renderThrowsExceptionForNotAllowedVariableData()
659 $this->addMockViewToSubject();
668 $this->expectException(\InvalidArgumentException
::class);
669 $this->expectExceptionCode(1288095720);
670 $this->subject
->render($configuration);
676 public function renderThrowsExceptionForNotAllowedVariableCurrent()
678 $this->addMockViewToSubject();
687 $this->expectException(\InvalidArgumentException
::class);
688 $this->expectExceptionCode(1288095720);
689 $this->subject
->render($configuration);
695 public function renderCallsCObjGetSingleForAllowedVariable()
697 $this->addMockViewToSubject();
706 $this->contentObjectRenderer
707 ->expects($this->once())
708 ->method('cObjGetSingle')
709 ->with('TEXT', ['value' => 'foo']);
710 $this->subject
->render($configuration);
716 public function renderAssignsRenderedContentObjectVariableToView()
718 $this->addMockViewToSubject();
727 $this->contentObjectRenderer
728 ->expects($this->once())
729 ->method('cObjGetSingle')
730 ->will($this->returnValue('foo'));
731 $this->standaloneView
732 ->expects($this->once())
733 ->method('assignMultiple')
734 ->with(['aVar' => 'foo', 'data' => [], 'current' => null]);
735 $this->subject
->render($configuration);
741 public function renderAssignsContentObjectRendererDataToView()
743 $this->addMockViewToSubject();
744 $this->contentObjectRenderer
->data
= ['foo'];
745 $this->standaloneView
746 ->expects($this->once())
747 ->method('assignMultiple')
748 ->with(['data' => ['foo'], 'current' => null]);
749 $this->subject
->render([]);
755 public function renderAssignsContentObjectRendererCurrentValueToView()
757 $this->addMockViewToSubject();
758 $this->contentObjectRenderer
->data
= ['currentKey' => 'currentValue'];
759 $this->contentObjectRenderer
->currentValKey
= 'currentKey';
760 $this->standaloneView
761 ->expects($this->once())
762 ->method('assignMultiple')
763 ->with(['data' => ['currentKey' => 'currentValue'], 'current' => 'currentValue']);
764 $this->subject
->render([]);
770 public function renderCallsRenderOnStandaloneViewie()
772 $this->addMockViewToSubject();
773 $this->standaloneView
774 ->expects($this->once())
776 $this->subject
->render([]);
782 public function renderCallsStandardWrapOnResultStringIfGivenInConfiguration()
784 $this->addMockViewToSubject();
790 $this->standaloneView
791 ->expects($this->any())
793 ->will($this->returnValue('baz'));
794 $this->contentObjectRenderer
795 ->expects($this->once())
797 ->with('baz', ['foo' => 'bar']);
798 $this->subject
->render($configuration);
802 * @param TemplateView $viewMock
803 * @param string|null $expectedHeader
804 * @param string|null $expectedFooter
806 * @dataProvider headerAssetDataProvider
808 public function renderFluidTemplateAssetsIntoPageRendererRendersAndAttachesAssets($viewMock, $expectedHeader, $expectedFooter)
810 $pageRendererMock = $this->getMockBuilder(PageRenderer
::class)->setMethods(['addHeaderData', 'addFooterData'])->getMock();
811 if (!empty(trim($expectedHeader))) {
812 $pageRendererMock->expects($this->once())->method('addHeaderData')->with($expectedHeader);
814 $pageRendererMock->expects($this->never())->method('addHeaderData');
816 if (!empty(trim($expectedFooter))) {
817 $pageRendererMock->expects($this->once())->method('addFooterData')->with($expectedFooter);
819 $pageRendererMock->expects($this->never())->method('addFooterData');
821 $subject = $this->getMockBuilder(FluidTemplateContentObject
::class)->setMethods(['getPageRenderer'])->disableOriginalConstructor()->getMock();
822 $subject->expects($this->once())->method('getPageRenderer')->willReturn($pageRendererMock);
823 $viewProperty = new \
ReflectionProperty($subject, 'view');
824 $viewProperty->setAccessible(true);
825 $viewProperty->setValue($subject, $viewMock);
827 $method = new \
ReflectionMethod($subject, 'renderFluidTemplateAssetsIntoPageRenderer');
828 $method->setAccessible(true);
829 $method->invoke($subject);
835 public function headerAssetDataProvider()
837 $viewWithHeaderData = $this->getMockBuilder(TemplateView
::class)->setMethods(['renderSection'])->disableOriginalConstructor()->getMock();
838 $viewWithHeaderData->expects($this->at(0))->method('renderSection')->with('HeaderAssets', $this->anything(), true)->willReturn('custom-header-data');
839 $viewWithHeaderData->expects($this->at(1))->method('renderSection')->with('FooterAssets', $this->anything(), true)->willReturn(null);
840 $viewWithFooterData = $this->getMockBuilder(TemplateView
::class)->setMethods(['renderSection'])->disableOriginalConstructor()->getMock();
841 $viewWithFooterData->expects($this->at(0))->method('renderSection')->with('HeaderAssets', $this->anything(), true)->willReturn(null);
842 $viewWithFooterData->expects($this->at(1))->method('renderSection')->with('FooterAssets', $this->anything(), true)->willReturn('custom-footer-data');
843 $viewWithBothData = $this->getMockBuilder(TemplateView
::class)->setMethods(['renderSection'])->disableOriginalConstructor()->getMock();
844 $viewWithBothData->expects($this->at(0))->method('renderSection')->with('HeaderAssets', $this->anything(), true)->willReturn('custom-header-data');
845 $viewWithBothData->expects($this->at(1))->method('renderSection')->with('FooterAssets', $this->anything(), true)->willReturn('custom-footer-data');
847 [$viewWithHeaderData, 'custom-header-data', null],
848 [$viewWithFooterData, null, 'custom-footer-data'],
849 [$viewWithBothData, 'custom-header-data', 'custom-footer-data']