9e270f9423097f27b22e96c218bddd0e8b564f77
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Functional / Page / PageRendererTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Functional\Page;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
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.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Page\PageRenderer;
18
19 /**
20 * Test case
21 */
22 class PageRendererTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase
23 {
24 /**
25 * @test
26 */
27 public function pageRendererRendersInsertsMainContentStringsInOutput()
28 {
29 $subject = new PageRenderer();
30 $subject->setCharSet('utf-8');
31 $subject->setLanguage('default');
32
33 $prologueString = $expectedPrologueString = '<?xml version="1.0" encoding="utf-8" ?>';
34 $subject->setXmlPrologAndDocType($prologueString);
35
36 $title = $this->getUniqueId('aTitle-');
37 $subject->setTitle($title);
38 $expectedTitleString = '<title>' . $title . '</title>';
39
40 $charset = 'utf-8';
41 $subject->setCharSet($charset);
42 $expectedCharsetString = '<meta http-equiv="Content-Type" content="text/html; charset=' . $charset . '" />';
43
44 $favouriteIcon = 'http://google.com/favicon.ico';
45 $subject->setFavIcon($favouriteIcon);
46 $expectedFavouriteIconPartOne = '<link rel="shortcut icon" href="' . $favouriteIcon . '" />';
47
48 $baseUrl = 'http://google.com/';
49 $subject->setBaseUrl($baseUrl);
50 $expectedBaseUrlString = '<base href="' . $baseUrl . '" />';
51
52 $subject->setMetaTag('property', 'og:type', 'foobar');
53 $subject->setMetaTag('name', 'author', 'husel');
54 $subject->setMetaTag('name', 'author', 'foobar');
55 $subject->setMetaTag('http-equiv', 'refresh', '5');
56 $subject->setMetaTag('name', 'DC.Author', '<evil tag>');
57 $subject->setMetaTag('property', 'og:image', '/path/to/image1.jpg', [], false);
58 $subject->setMetaTag('property', 'og:image', '/path/to/image2.jpg', [], false);
59
60 // Unset meta tag
61 $subject->setMetaTag('NaMe', 'randomTag', 'foobar');
62 $subject->removeMetaTag('name', 'RanDoMtAg');
63
64 $inlineComment = $this->getUniqueId('comment');
65 $subject->addInlineComment($inlineComment);
66 $expectedInlineCommentString = '<!-- ' . LF . $inlineComment . '-->';
67
68 $headerData = $expectedHeaderData = '<tag method="private" name="test" />';
69 $subject->addHeaderData($headerData);
70
71 $subject->addJsLibrary('test', 'fileadmin/test.js', 'text/javascript', false, false, 'wrapBeforeXwrapAfter', false, 'X');
72 $expectedJsLibraryRegExp = '#wrapBefore<script src="fileadmin/test\\.(js|\\d+\\.js|js\\?\\d+)" type="text/javascript"></script>wrapAfter#';
73
74 $subject->addJsFile('fileadmin/test.js', 'text/javascript', false, false, 'wrapBeforeXwrapAfter', false, 'X');
75 $expectedJsFileRegExp = '#wrapBefore<script src="fileadmin/test\\.(js|\\d+\\.js|js\\?\\d+)" type="text/javascript"></script>wrapAfter#';
76
77 $jsInlineCode = $expectedJsInlineCodeString = 'var x = "' . $this->getUniqueId('jsInline-') . '"';
78 $subject->addJsInlineCode($this->getUniqueId(), $jsInlineCode);
79
80 $cssFile = $this->getUniqueId('cssFile-');
81 $expectedCssFileString = 'wrapBefore<link rel="stylesheet" type="text/css" href="' . $cssFile . '" media="print" />wrapAfter';
82 $subject->addCssFile($cssFile, 'stylesheet', 'print', '', true, false, 'wrapBeforeXwrapAfter', false, 'X');
83
84 $expectedCssInlineBlockOnTopString = '/*general3*/' . LF . 'h1 {margin:20px;}' . LF . '/*general2*/' . LF . 'body {margin:20px;}';
85 $subject->addCssInlineBlock('general2', 'body {margin:20px;}');
86 $subject->addCssInlineBlock('general3', 'h1 {margin:20px;}', null, true);
87
88 $subject->loadJquery();
89 $expectedJqueryRegExp = '#<script src="typo3/sysext/core/Resources/Public/JavaScript/Contrib/jquery/jquery\\.min\\.(js|\\d+\\.js|js\\?\\d+)" type="text/javascript"></script>#';
90
91 $expectedBodyContent = $this->getUniqueId('ABCDE-');
92 $subject->setBodyContent($expectedBodyContent);
93
94 $renderedString = $subject->render();
95
96 $this->assertContains($expectedPrologueString, $renderedString);
97 $this->assertContains($expectedTitleString, $renderedString);
98 $this->assertContains($expectedCharsetString, $renderedString);
99 $this->assertContains($expectedFavouriteIconPartOne, $renderedString);
100 $this->assertContains($expectedBaseUrlString, $renderedString);
101 $this->assertContains($expectedInlineCommentString, $renderedString);
102 $this->assertContains($expectedHeaderData, $renderedString);
103 $this->assertRegExp($expectedJsLibraryRegExp, $renderedString);
104 $this->assertRegExp($expectedJsFileRegExp, $renderedString);
105 $this->assertContains($expectedJsInlineCodeString, $renderedString);
106 $this->assertContains($expectedCssFileString, $renderedString);
107 $this->assertContains($expectedCssInlineBlockOnTopString, $renderedString);
108 $this->assertRegExp($expectedJqueryRegExp, $renderedString);
109 $this->assertContains($expectedBodyContent, $renderedString);
110 $this->assertContains('<meta property="og:type" content="foobar" />', $renderedString);
111 $this->assertContains('<meta name="author" content="foobar" />', $renderedString);
112 $this->assertContains('<meta http-equiv="refresh" content="5" />', $renderedString);
113 $this->assertContains('<meta name="dc.author" content="&lt;evil tag&gt;" />', $renderedString);
114 $this->assertNotContains('<meta name="randomtag" content="foobar">', $renderedString);
115 $this->assertNotContains('<meta name="randomtag" content="foobar" />', $renderedString);
116 $this->assertContains('<meta name="generator" content="TYPO3 CMS" />', $renderedString);
117 $this->assertContains('<meta property="og:image" content="/path/to/image1.jpg" />', $renderedString);
118 $this->assertContains('<meta property="og:image" content="/path/to/image2.jpg" />', $renderedString);
119 }
120
121 /**
122 * @test
123 */
124 public function pageRendererRendersFooterValues()
125 {
126 $subject = new PageRenderer();
127 $subject->setCharSet('utf-8');
128 $subject->setLanguage('default');
129
130 $subject->enableMoveJsFromHeaderToFooter();
131
132 $footerData = $expectedFooterData = '<tag method="private" name="test" />';
133 $subject->addFooterData($footerData);
134
135 $expectedJsFooterLibraryRegExp = '#wrapBefore<script src="fileadmin/test\\.(js|\\d+\\.js|js\\?\\d+)" type="text/javascript"></script>wrapAfter#';
136 $subject->addJsFooterLibrary('test', 'fileadmin/test.js', 'text/javascript', false, false, 'wrapBeforeXwrapAfter', false, 'X');
137
138 $expectedJsFooterRegExp = '#wrapBefore<script src="fileadmin/test\\.(js|\\d+\\.js|js\\?\\d+)" type="text/javascript"></script>wrapAfter#';
139 $subject->addJsFooterFile('fileadmin/test.js', 'text/javascript', false, false, 'wrapBeforeXwrapAfter', false, 'X');
140
141 $jsFooterInlineCode = $expectedJsFooterInlineCodeString = 'var x = "' . $this->getUniqueId('jsFooterInline-') . '"';
142 $subject->addJsFooterInlineCode($this->getUniqueId(), $jsFooterInlineCode);
143
144 // Bunch of label tests
145 $subject->addInlineLanguageLabel('myKey', 'myValue');
146 $subject->addInlineLanguageLabelArray([
147 'myKeyArray1' => 'myValueArray1',
148 'myKeyArray2' => 'myValueArray2'
149 ]);
150 $subject->addInlineLanguageLabelArray([
151 'myKeyArray3' => 'myValueArray3'
152 ]);
153 $expectedInlineLabelReturnValue = 'TYPO3.lang = {"myKey":"myValue","myKeyArray1":"myValueArray1","myKeyArray2":"myValueArray2","myKeyArray3":"myValueArray3"';
154
155 $subject->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/locallang_core.xlf');
156 $expectedLanguageLabel1 = 'labels.beUser';
157 $expectedLanguageLabel2 = 'labels.feUser';
158
159 // Bunch of inline settings test
160 $subject->addInlineSetting('myApp', 'myKey', 'myValue');
161 $subject->addInlineSettingArray('myApp', [
162 'myKey1' => 'myValue1',
163 'myKey2' => 'myValue2'
164 ]);
165 $subject->addInlineSettingArray('myApp', [
166 'myKey3' => 'myValue3'
167 ]);
168 $expectedInlineSettingsReturnValue = 'TYPO3.settings = {"myApp":{"myKey":"myValue","myKey1":"myValue1","myKey2":"myValue2","myKey3":"myValue3"}';
169
170 $renderedString = $subject->render(PageRenderer::PART_FOOTER);
171
172 $this->assertContains($expectedFooterData, $renderedString);
173 $this->assertRegExp($expectedJsFooterLibraryRegExp, $renderedString);
174 $this->assertRegExp($expectedJsFooterRegExp, $renderedString);
175 $this->assertContains($expectedJsFooterInlineCodeString, $renderedString);
176 $this->assertContains($expectedInlineLabelReturnValue, $renderedString);
177 $this->assertContains($expectedLanguageLabel1, $renderedString);
178 $this->assertContains($expectedLanguageLabel2, $renderedString);
179 $this->assertContains($expectedInlineSettingsReturnValue, $renderedString);
180 }
181
182 /**
183 * @return array
184 */
185 public function jqueryNamespaceDataProvider()
186 {
187 return [
188 'Custom namespace falls back to "no conflict"' => [
189 'namespace' => 'MyNameSpace',
190 'matchNoConflict' => true,
191 ],
192 '"None" namespace is respected' => [
193 'namespace' => PageRenderer::JQUERY_NAMESPACE_NONE,
194 'matchNoConflict' => false,
195 ],
196 ];
197 }
198
199 /**
200 * @param string $namespace
201 * @param bool $matchNoConflict
202 * @test
203 * @dataProvider jqueryNamespaceDataProvider
204 */
205 public function loadJqueryRespectsNamespace($namespace, $matchNoConflict)
206 {
207 $subject = new PageRenderer();
208
209 $expectedRegExp = '#<script src="typo3/sysext/core/Resources/Public/JavaScript/Contrib/jquery/jquery\\.min\\.(js|\\d+\\.js|js\\?\\d+)" type="text/javascript"></script>#';
210 $noConflictStatement = 'jQuery.noConflict();';
211 $subject->loadJquery(null, null, $namespace);
212
213 //jQuery.noConflict();
214 $out = $subject->render();
215 $this->assertRegExp($expectedRegExp, $out);
216
217 if ($matchNoConflict) {
218 $this->assertContains($noConflictStatement, $out);
219 } else {
220 $this->assertNotContains($noConflictStatement, $out);
221 }
222 }
223
224 /**
225 * @test
226 */
227 public function loadJqueryWithDefaultNoConflictModeDoesNotSetNamespace()
228 {
229 $subject = new PageRenderer();
230
231 $expectedRegExp = '#<script src="typo3/sysext/core/Resources/Public/JavaScript/Contrib/jquery/jquery\\.min\\.(js|\\d+\\.js|js\\?\\d+)" type="text/javascript"></script>#';
232 $expectedStatement = 'jQuery.noConflict();';
233 $subject->loadJquery(null, null, 'MyNameSpace');
234 $out = $subject->render();
235 $this->assertRegExp($expectedRegExp, $out);
236 $this->assertContains($expectedStatement, $out);
237 $this->assertNotContains('var TYPO3 = TYPO3 || {}; TYPO3.', $out);
238 }
239
240 /**
241 * @test
242 */
243 public function loadJqueryWithNamespaceNoneDoesNotIncludeNoConflictHandling()
244 {
245 $subject = new PageRenderer();
246
247 $expectedRegExp = '#<script src="typo3/sysext/core/Resources/Public/JavaScript/Contrib/jquery/jquery\\.min\\.(js|\\d+\\.js|js\\?\\d+)" type="text/javascript"></script>#';
248 $subject->loadJquery(null, null, PageRenderer::JQUERY_NAMESPACE_NONE);
249 $out = $subject->render();
250 $this->assertRegExp($expectedRegExp, $out);
251 $this->assertNotContains('jQuery.noConflict', $out);
252 }
253
254 /**
255 * @test
256 */
257 public function loadJqueryLoadsTheLatestJqueryVersionInNoConflictModeUncompressedInDebugMode()
258 {
259 $subject = new PageRenderer();
260
261 $expectedRegExp = '#<script src="typo3/sysext/core/Resources/Public/JavaScript/Contrib/jquery/jquery\\.(js|\\d+\\.js|js\\?\\d+)" type="text/javascript"></script>#';
262 $expectedStatement = 'jQuery.noConflict();';
263 $subject->loadJquery(null, null, 'MyNameSpace');
264 $subject->enableDebugMode();
265 $out = $subject->render();
266 $this->assertRegExp($expectedRegExp, $out);
267 $this->assertContains($expectedStatement, $out);
268 }
269
270 /**
271 * @return array
272 */
273 public function loadJqueryFromSourceDataProvider()
274 {
275 return [
276 'google with version number' => [
277 '1.6.3',
278 'google',
279 '#<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.js" type="text/javascript"></script>#'
280 ],
281 'msn with version number' => [
282 '1.6.3',
283 'msn',
284 '#<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.3.js" type="text/javascript"></script>#'
285 ],
286 'jquery with version number' => [
287 '1.6.3',
288 'jquery',
289 '#<script src="https://code.jquery.com/jquery-1.6.3.js" type="text/javascript"></script>#'
290 ],
291 'jquery with custom URL' => [
292 '1.6.3',
293 'https://my.cool.cdn/foo/jquery.js',
294 '#<script src="https://my.cool.cdn/foo/jquery.js" type="text/javascript"></script>#'
295 ],
296 ];
297 }
298
299 /**
300 * @param string $version
301 * @param string $source
302 * @param string $regex
303 * @dataProvider loadJqueryFromSourceDataProvider
304 * @test
305 */
306 public function isJqueryLoadedFromSourceUncompressedIfDebugModeIsEnabled($version, $source, $regex)
307 {
308 $subject = new PageRenderer();
309
310 $subject->loadJquery($version, $source);
311 $subject->enableDebugMode();
312 $out = $subject->render();
313 $this->assertRegExp($regex, $out);
314 }
315
316 /**
317 * @test
318 */
319 public function isJqueryLoadedMinifiedFromGoogleByDefault()
320 {
321 $subject = new PageRenderer();
322
323 $expectedRegex = '#<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js" type="text/javascript"></script>#';
324 $subject->loadJquery('1.6.3', 'google');
325 $out = $subject->render();
326 $this->assertRegExp($expectedRegex, $out);
327 }
328 }