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