294ece936fe46168f52447566739986159c40a18
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / Functional / SiteHandling / LinkGeneratorTest.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Frontend\Tests\Functional\SiteHandling;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Core\Core\Bootstrap;
20 use TYPO3\CMS\Core\TypoScript\TemplateService;
21 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory;
22 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter;
23 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\TypoScriptInstruction;
24 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
25 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequestContext;
26
27 /**
28 * Test case for frontend requests not having site handling configured
29 * (aka testing legacy link generation)
30 */
31 class LinkGeneratorTest extends AbstractTestCase
32 {
33 /**
34 * @var string
35 */
36 private $siteTitle = 'A Company that Manufactures Everything Inc';
37
38 /**
39 * @var InternalRequestContext
40 */
41 private $internalRequestContext;
42
43 public static function setUpBeforeClass()
44 {
45 parent::setUpBeforeClass();
46 static::initializeDatabaseSnapshot();
47 }
48
49 public static function tearDownAfterClass()
50 {
51 static::destroyDatabaseSnapshot();
52 parent::tearDownAfterClass();
53 }
54
55 protected function setUp()
56 {
57 parent::setUp();
58
59 // these settings are forwarded to the frontend sub-request as well
60 $this->internalRequestContext = (new InternalRequestContext())
61 ->withGlobalSettings(['TYPO3_CONF_VARS' => static::TYPO3_CONF_VARS]);
62
63 $this->withDatabaseSnapshot(function () {
64 $this->setUpDatabase();
65 });
66 }
67
68 protected function setUpDatabase()
69 {
70 $backendUser = $this->setUpBackendUserFromFixture(1);
71 Bootstrap::initializeLanguageObject();
72
73 $scenarioFile = __DIR__ . '/Fixtures/PlainScenario.yaml';
74 $factory = DataHandlerFactory::fromYamlFile($scenarioFile);
75 $writer = DataHandlerWriter::withBackendUser($backendUser);
76 $writer->invokeFactory($factory);
77 static::failIfArrayIsNotEmpty(
78 $writer->getErrors()
79 );
80
81 $this->setUpFrontendRootPage(
82 1000,
83 [
84 'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/LinkGenerator.typoscript',
85 ],
86 [
87 'title' => 'ACME Root',
88 'sitetitle' => $this->siteTitle,
89 ]
90 );
91 $this->setUpFrontendRootPage(
92 2000,
93 [
94 'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/LinkGenerator.typoscript',
95 ],
96 [
97 'title' => 'ACME Blog',
98 'sitetitle' => $this->siteTitle,
99 ]
100 );
101 }
102
103 protected function tearDown()
104 {
105 unset($this->internalRequestContext);
106 parent::tearDown();
107 }
108
109 /**
110 * @return array
111 */
112 public function linkIsGeneratedDataProvider(): array
113 {
114 $instructions = [
115 // acme.com -> acme.com (same site)
116 [1100, 1000, 'index.php?id=acme-root'],
117 [1100, 1100, 'index.php?id=acme-first'],
118 [1100, 1200, 'index.php?id=1200'],
119 [1100, 1210, 'index.php?id=1210'],
120 [1100, 404, 'index.php?id=404'],
121 // acme.com -> products.acme.com (nested sub-site)
122 [1100, 1300, 'index.php?id=1300'],
123 [1100, 1310, 'index.php?id=1310'],
124 // acme.com -> blog.acme.com (different site)
125 [1100, 2000, 'index.php?id=blog-root'],
126 [1100, 2100, 'index.php?id=2100'],
127 [1100, 2110, 'index.php?id=2110'],
128 [1100, 2111, 'index.php?id=2111'],
129 // blog.acme.com -> acme.com (different site)
130 [2100, 1000, 'index.php?id=acme-root'],
131 [2100, 1100, 'index.php?id=acme-first'],
132 [2100, 1200, 'index.php?id=1200'],
133 [2100, 1210, 'index.php?id=1210'],
134 [2100, 404, 'index.php?id=404'],
135 // blog.acme.com -> products.acme.com (different sub-site)
136 [2100, 1300, 'index.php?id=1300'],
137 [2100, 1310, 'index.php?id=1310'],
138 ];
139
140 return $this->keysFromTemplate(
141 $instructions,
142 '%1$d->%2$d'
143 );
144 }
145
146 /**
147 * @param int $sourcePageId
148 * @param int $targetPageId
149 * @param string $expectation
150 *
151 * @test
152 * @dataProvider linkIsGeneratedDataProvider
153 */
154 public function linkIsGenerated(int $sourcePageId, int $targetPageId, string $expectation)
155 {
156 $response = $this->executeFrontendRequest(
157 (new InternalRequest())
158 ->withPageId($sourcePageId)
159 ->withInstructions([
160 $this->createTypoLinkUrlInstruction([
161 'parameter' => $targetPageId,
162 ])
163 ]),
164 $this->internalRequestContext
165 );
166
167 static::assertSame($expectation, (string)$response->getBody());
168 }
169
170 /**
171 * @return array
172 */
173 public function linkIsGeneratedFromMountPointDataProvider(): array
174 {
175 $instructions = [
176 // acme.com -> acme.com (same site)
177 [[7100, 1700], 7110, 1000, 'index.php?id=acme-root'],
178 [[7100, 1700], 7110, 1100, 'index.php?id=acme-first'],
179 [[7100, 1700], 7110, 1200, 'index.php?id=1200'],
180 [[7100, 1700], 7110, 1210, 'index.php?id=1210'],
181 [[7100, 1700], 7110, 404, 'index.php?id=404'],
182 // acme.com -> products.acme.com (nested sub-site)
183 [[7100, 1700], 7110, 1300, 'index.php?id=1300'],
184 [[7100, 1700], 7110, 1310, 'index.php?id=1310'],
185 // acme.com -> blog.acme.com (different site)
186 [[7100, 1700], 7110, 2000, 'index.php?id=blog-root'],
187 [[7100, 1700], 7110, 2100, 'index.php?id=2100'],
188 [[7100, 1700], 7110, 2110, 'index.php?id=2110'],
189 [[7100, 1700], 7110, 2111, 'index.php?id=2111'],
190 // blog.acme.com -> acme.com (different site)
191 [[7100, 2700], 7110, 1000, 'index.php?id=acme-root'],
192 [[7100, 2700], 7110, 1100, 'index.php?id=acme-first'],
193 [[7100, 2700], 7110, 1200, 'index.php?id=1200'],
194 [[7100, 2700], 7110, 1210, 'index.php?id=1210'],
195 [[7100, 2700], 7110, 404, 'index.php?id=404'],
196 // blog.acme.com -> products.acme.com (different sub-site)
197 [[7100, 2700], 7110, 1300, 'index.php?id=1300'],
198 [[7100, 2700], 7110, 1310, 'index.php?id=1310'],
199 ];
200
201 return $this->keysFromTemplate(
202 $instructions,
203 '%2$d->%3$d (mount:%1$s)',
204 function (array $items) {
205 array_splice(
206 $items,
207 0,
208 1,
209 [implode('->', $items[0])]
210 );
211 return $items;
212 }
213 );
214 }
215
216 /**
217 * @param array $pageMount
218 * @param int $sourcePageId
219 * @param int $targetPageId
220 * @param string $expectation
221 *
222 * @test
223 * @dataProvider linkIsGeneratedFromMountPointDataProvider
224 */
225 public function linkIsGeneratedFromMountPoint(array $pageMount, int $sourcePageId, int $targetPageId, string $expectation)
226 {
227 // @todo Fix mount point resolving for for pseudo-sites
228 // (PseudoSite should be resolved based on MP-value instead of ID in middleware)
229 $this->markTestSkipped('Mount points currently cannot be resolved in legacy mode');
230
231 $response = $this->executeFrontendRequest(
232 (new InternalRequest())
233 ->withMountPoint(...$pageMount)
234 ->withPageId($sourcePageId)
235 ->withInstructions([
236 $this->createTypoLinkUrlInstruction([
237 'parameter' => $targetPageId,
238 ])
239 ]),
240 $this->internalRequestContext
241 );
242
243 static::assertSame($expectation, (string)$response->getBody());
244 }
245
246 /**
247 * @return array
248 */
249 public function linkIsGeneratedForLanguageDataProvider(): array
250 {
251 $instructions = [
252 // acme.com -> acme.com (same site)
253 [1100, 1100, 0, 'index.php?id=acme-first&L=0'],
254 [1100, 1100, 1, 'index.php?id=acme-first&L=1'],
255 [1100, 1100, 2, 'index.php?id=acme-first&L=2'],
256 [1100, 1101, 0, 'index.php?id=acme-first&L=1'],
257 [1100, 1102, 0, 'index.php?id=acme-first&L=2'],
258 // acme.com -> products.acme.com (nested sub-site)
259 [1100, 1300, 0, 'index.php?id=1300&L=0'],
260 [1100, 1310, 0, 'index.php?id=1310&L=0'],
261 // acme.com -> products.acme.com (nested sub-site, l18n_cfg=1)
262 [1100, 1410, 0, ''],
263 [1100, 1410, 1, 'index.php?id=1410&L=1'],
264 [1100, 1410, 2, 'index.php?id=1410&L=2'],
265 [1100, 1411, 0, 'index.php?id=1410&L=1'],
266 [1100, 1412, 0, 'index.php?id=1410&L=2'],
267 // acme.com -> archive (outside site)
268 [1100, 3100, 0, 'index.php?id=3100&L=0'],
269 [1100, 3100, 1, 'index.php?id=3100&L=1'],
270 [1100, 3100, 2, 'index.php?id=3100&L=2'],
271 [1100, 3101, 0, 'index.php?id=3100&L=1'],
272 [1100, 3102, 0, 'index.php?id=3100&L=2'],
273 // blog.acme.com -> acme.com (different site)
274 [2100, 1100, 0, 'index.php?id=acme-first&L=0'],
275 [2100, 1100, 1, 'index.php?id=acme-first&L=1'],
276 [2100, 1100, 2, 'index.php?id=acme-first&L=2'],
277 [2100, 1101, 0, 'index.php?id=acme-first&L=1'],
278 [2100, 1102, 0, 'index.php?id=acme-first&L=2'],
279 // blog.acme.com -> archive (outside site)
280 [2100, 3100, 0, 'index.php?id=3100&L=0'],
281 [2100, 3100, 1, 'index.php?id=3100&L=1'],
282 [2100, 3100, 2, 'index.php?id=3100&L=2'],
283 [2100, 3101, 0, 'index.php?id=3100&L=1'],
284 [2100, 3102, 0, 'index.php?id=3100&L=2'],
285 // blog.acme.com -> products.acme.com (different sub-site)
286 [2100, 1300, 0, 'index.php?id=1300&L=0'],
287 [2100, 1310, 0, 'index.php?id=1310&L=0'],
288 ];
289
290 return $this->keysFromTemplate(
291 $instructions,
292 '%1$d->%2$d (lang:%3$d)'
293 );
294 }
295
296 /**
297 * @param int $sourcePageId
298 * @param int $targetPageId
299 * @param int $targetLanguageId
300 * @param string $expectation
301 *
302 * @test
303 * @dataProvider linkIsGeneratedForLanguageDataProvider
304 */
305 public function linkIsGeneratedForLanguage(int $sourcePageId, int $targetPageId, int $targetLanguageId, string $expectation)
306 {
307 $response = $this->executeFrontendRequest(
308 (new InternalRequest())
309 ->withPageId($sourcePageId)
310 ->withInstructions([
311 $this->createTypoLinkUrlInstruction([
312 'parameter' => $targetPageId,
313 'additionalParams' => '&L=' . $targetLanguageId,
314 ])
315 ]),
316 $this->internalRequestContext
317 );
318
319 static::assertSame($expectation, (string)$response->getBody());
320 }
321
322 /**
323 * @return array
324 */
325 public function linkIsGeneratedWithQueryParametersDataProvider(): array
326 {
327 $instructions = [
328 // acme.com -> acme.com (same site)
329 [1100, 1000, 'index.php?id=acme-root&testing%5Bvalue%5D=1&cHash=7d1f13fa91159dac7feb3c824936b39d'],
330 [1100, 1100, 'index.php?id=acme-first&testing%5Bvalue%5D=1&cHash=f42b850e435f0cedd366f5db749fc1af'],
331 [1100, 1200, 'index.php?id=1200&testing%5Bvalue%5D=1&cHash=784e11c50ea1a13fd7d969df4ec53ea3'],
332 [1100, 1210, 'index.php?id=1210&testing%5Bvalue%5D=1&cHash=ccb7067022b9835ebfd8f720722bc708'],
333 [1100, 404, 'index.php?id=404&testing%5Bvalue%5D=1&cHash=864e96f586a78a53452f3bf0f4d24591'],
334 // acme.com -> products.acme.com (nested sub-site)
335 [1100, 1300, 'index.php?id=1300&testing%5Bvalue%5D=1&cHash=dbd6597d72ed5098cce3d03eac1eeefe'],
336 [1100, 1310, 'index.php?id=1310&testing%5Bvalue%5D=1&cHash=e64bfc7ab7dd6b70d161e4d556be9726'],
337 // acme.com -> blog.acme.com (different site)
338 [1100, 2000, 'index.php?id=blog-root&testing%5Bvalue%5D=1&cHash=a14da633e46dba71640cb85226cd12c5'],
339 [1100, 2100, 'index.php?id=2100&testing%5Bvalue%5D=1&cHash=d23d74cb50383f8788a9930ec8ba679f'],
340 [1100, 2110, 'index.php?id=2110&testing%5Bvalue%5D=1&cHash=bf25eea89f44a9a79dabdca98f38a432'],
341 [1100, 2111, 'index.php?id=2111&testing%5Bvalue%5D=1&cHash=42dbaeb9172b6b1ca23b49941e194db2'],
342 // blog.acme.com -> acme.com (different site)
343 [2100, 1000, 'index.php?id=acme-root&testing%5Bvalue%5D=1&cHash=7d1f13fa91159dac7feb3c824936b39d'],
344 [2100, 1100, 'index.php?id=acme-first&testing%5Bvalue%5D=1&cHash=f42b850e435f0cedd366f5db749fc1af'],
345 [2100, 1200, 'index.php?id=1200&testing%5Bvalue%5D=1&cHash=784e11c50ea1a13fd7d969df4ec53ea3'],
346 [2100, 1210, 'index.php?id=1210&testing%5Bvalue%5D=1&cHash=ccb7067022b9835ebfd8f720722bc708'],
347 [2100, 404, 'index.php?id=404&testing%5Bvalue%5D=1&cHash=864e96f586a78a53452f3bf0f4d24591'],
348 // blog.acme.com -> products.acme.com (different sub-site)
349 [2100, 1300, 'index.php?id=1300&testing%5Bvalue%5D=1&cHash=dbd6597d72ed5098cce3d03eac1eeefe'],
350 [2100, 1310, 'index.php?id=1310&testing%5Bvalue%5D=1&cHash=e64bfc7ab7dd6b70d161e4d556be9726'],
351 ];
352
353 return $this->keysFromTemplate(
354 $instructions,
355 '%1$d->%2$d'
356 );
357 }
358
359 /**
360 * @param int $sourcePageId
361 * @param int $targetPageId
362 * @param string $expectation
363 *
364 * @test
365 * @dataProvider linkIsGeneratedWithQueryParametersDataProvider
366 */
367 public function linkIsGeneratedWithQueryParameters(int $sourcePageId, int $targetPageId, string $expectation)
368 {
369 $response = $this->executeFrontendRequest(
370 (new InternalRequest())
371 ->withPageId($sourcePageId)
372 ->withInstructions([
373 $this->createTypoLinkUrlInstruction([
374 'parameter' => $targetPageId,
375 'additionalParams' => '&testing[value]=1',
376 'useCacheHash' => 1,
377 ])
378 ]),
379 $this->internalRequestContext
380 );
381
382 static::assertSame($expectation, (string)$response->getBody());
383 }
384
385 /**
386 * @return array
387 */
388 public function linkIsGeneratedForRestrictedPageDataProvider(): array
389 {
390 $instructions = [
391 [1100, 1510, 0, ''],
392 // [1100, 1511, 0, ''], // @todo Fails, not expanded to sub-pages
393 [1100, 1512, 0, ''],
394 [1100, 1515, 0, ''],
395 [1100, 1520, 0, ''],
396 // [1100, 1521, 0, ''], // @todo Fails, not expanded to sub-pages
397 //
398 [1100, 1510, 1, 'index.php?id=1510'],
399 [1100, 1511, 1, 'index.php?id=1511'],
400 [1100, 1512, 1, 'index.php?id=1512'],
401 [1100, 1515, 1, ''],
402 [1100, 1520, 1, ''],
403 // [1100, 1521, 1, ''], // @todo Fails, not expanded to sub-pages
404 //
405 [1100, 1510, 2, 'index.php?id=1510'],
406 [1100, 1511, 2, 'index.php?id=1511'],
407 [1100, 1512, 2, ''],
408 [1100, 1515, 2, 'index.php?id=1515'],
409 [1100, 1520, 2, 'index.php?id=1520'],
410 [1100, 1521, 2, 'index.php?id=1521'],
411 //
412 [1100, 1510, 3, 'index.php?id=1510'],
413 [1100, 1511, 3, 'index.php?id=1511'],
414 [1100, 1512, 3, 'index.php?id=1512'],
415 [1100, 1515, 3, 'index.php?id=1515'],
416 [1100, 1520, 3, 'index.php?id=1520'],
417 [1100, 1521, 3, 'index.php?id=1521'],
418 ];
419
420 return $this->keysFromTemplate(
421 $instructions,
422 '%1$d->%2$d (user:%3$d)'
423 );
424 }
425
426 /**
427 * @param int $sourcePageId
428 * @param int $targetPageId
429 * @param int $frontendUserId
430 * @param string $expectation
431 *
432 * @test
433 * @dataProvider linkIsGeneratedForRestrictedPageDataProvider
434 */
435 public function linkIsGeneratedForRestrictedPage(int $sourcePageId, int $targetPageId, int $frontendUserId, string $expectation)
436 {
437 $response = $this->executeFrontendRequest(
438 (new InternalRequest())
439 ->withPageId($sourcePageId)
440 ->withInstructions([
441 $this->createTypoLinkUrlInstruction([
442 'parameter' => $targetPageId,
443 ])
444 ]),
445 $this->internalRequestContext
446 ->withFrontendUserId($frontendUserId)
447 );
448
449 static::assertSame($expectation, (string)$response->getBody());
450 }
451
452 /**
453 * @return array
454 */
455 public function linkIsGeneratedForRestrictedPageUsingLoginPageDataProvider(): array
456 {
457 $instructions = [
458 // no frontend user given
459 [1100, 1510, 1500, 0, 'index.php?id=1500&pageId=1510'],
460 // [1100, 1511, 1500, 0, 'index.php?id=1500&pageId=1511'], // @todo Fails, not expanded to sub-pages
461 [1100, 1512, 1500, 0, 'index.php?id=1500&pageId=1512'],
462 [1100, 1515, 1500, 0, 'index.php?id=1500&pageId=1515'],
463 [1100, 1520, 1500, 0, 'index.php?id=1500&pageId=1520'],
464 // [1100, 1521, 1500, 0, 'index.php?id=1500&pageId=1521'], // @todo Fails, not expanded to sub-pages
465 // frontend user 1
466 [1100, 1510, 1500, 1, 'index.php?id=1510'],
467 [1100, 1511, 1500, 1, 'index.php?id=1511'],
468 [1100, 1512, 1500, 1, 'index.php?id=1512'],
469 [1100, 1515, 1500, 1, 'index.php?id=1500&pageId=1515'],
470 [1100, 1520, 1500, 1, 'index.php?id=1500&pageId=1520'],
471 // [1100, 1521, 1500, 1, 'index.php?id=1500&pageId=1521'], // @todo Fails, not expanded to sub-pages
472 // frontend user 2
473 [1100, 1510, 1500, 2, 'index.php?id=1510'],
474 [1100, 1511, 1500, 2, 'index.php?id=1511'],
475 [1100, 1512, 1500, 2, 'index.php?id=1500&pageId=1512'],
476 [1100, 1515, 1500, 2, 'index.php?id=1515'],
477 [1100, 1520, 1500, 2, 'index.php?id=1520'],
478 [1100, 1521, 1500, 2, 'index.php?id=1521'],
479 // frontend user 3
480 [1100, 1510, 1500, 3, 'index.php?id=1510'],
481 [1100, 1511, 1500, 3, 'index.php?id=1511'],
482 [1100, 1512, 1500, 3, 'index.php?id=1512'],
483 [1100, 1515, 1500, 3, 'index.php?id=1515'],
484 [1100, 1520, 1500, 3, 'index.php?id=1520'],
485 [1100, 1521, 1500, 3, 'index.php?id=1521'],
486 ];
487
488 return $this->keysFromTemplate(
489 $instructions,
490 '%1$d->%2$d (via: %3$d, user:%4$d)'
491 );
492 }
493
494 /**
495 * @param int $sourcePageId
496 * @param int $targetPageId
497 * @param int $loginPageId
498 * @param int $frontendUserId
499 * @param string $expectation
500 *
501 * @test
502 * @dataProvider linkIsGeneratedForRestrictedPageUsingLoginPageDataProvider
503 */
504 public function linkIsGeneratedForRestrictedPageUsingLoginPage(int $sourcePageId, int $targetPageId, int $loginPageId, int $frontendUserId, string $expectation)
505 {
506 $response = $this->executeFrontendRequest(
507 (new InternalRequest())
508 ->withPageId($sourcePageId)
509 ->withInstructions([
510 (new TypoScriptInstruction(TemplateService::class))
511 ->withTypoScript([
512 'config.' => [
513 'typolinkLinkAccessRestrictedPages' => $loginPageId,
514 'typolinkLinkAccessRestrictedPages_addParams' => '&pageId=###PAGE_ID###'
515 ],
516 ]),
517 $this->createTypoLinkUrlInstruction([
518 'parameter' => $targetPageId,
519 ])
520 ]),
521 $this->internalRequestContext
522 ->withFrontendUserId($frontendUserId)
523 );
524
525 static::assertSame($expectation, (string)$response->getBody());
526 }
527
528 /**
529 * @return array
530 */
531 public function linkIsGeneratedForPageVersionDataProvider(): array
532 {
533 // @todo Generation is not consistent "?id=" vs "index.php?id="
534 // -> most probably since pid=-1 is not correctly resolved
535 $instructions = [
536 // acme.com -> acme.com (same site)
537 [1100, 1100, false, 'index.php?id=acme-first'],
538 [1100, 1100, true, 'index.php?id=acme-first'], // @todo Alias not removed, yet
539 // [1100, 1950, false, 'index.php?id=1950'], // @todo Not generated for new-placeholder
540 [1100, 1950, true, 'index.php?id={targetPageId}'],
541 // blog.acme.com -> acme.com (different site)
542 [2100, 1100, false, 'index.php?id=acme-first'],
543 // @todo https://acme.us/ not prefixed for resolved version
544 [2100, 1100, true, 'index.php?id=acme-first'], // @todo Alias not removed, yet
545 // [2100, 1950, false, 'index.php?id=1950'], // @todo Not generated for new-placeholder
546 // @todo https://acme.us/ not prefixed for resolved version
547 [2100, 1950, true, 'index.php?id={targetPageId}'],
548 ];
549
550 return $this->keysFromTemplate(
551 $instructions,
552 '%1$d->%2$d (resolve:%3$d)'
553 );
554 }
555
556 /**
557 * @param int $sourcePageId
558 * @param int $targetPageId
559 * @param bool $resolveVersion
560 * @param string $expectation
561 *
562 * @test
563 * @dataProvider linkIsGeneratedForPageVersionDataProvider
564 */
565 public function linkIsGeneratedForPageVersion(int $sourcePageId, int $targetPageId, bool $resolveVersion, string $expectation)
566 {
567 $workspaceId = 1;
568 if ($resolveVersion) {
569 $targetPageId = BackendUtility::getWorkspaceVersionOfRecord(
570 $workspaceId,
571 'pages',
572 $targetPageId,
573 'uid'
574 )['uid'] ?? null;
575 }
576
577 $response = $this->executeFrontendRequest(
578 (new InternalRequest())
579 ->withPageId($sourcePageId)
580 ->withInstructions([
581 $this->createTypoLinkUrlInstruction([
582 'parameter' => $targetPageId,
583 ])
584 ]),
585 $this->internalRequestContext
586 ->withWorkspaceId($workspaceId)
587 );
588
589 $expectation = str_replace(
590 ['{targetPageId}'],
591 [$targetPageId],
592 $expectation
593 );
594
595 static::assertSame($expectation, (string)$response->getBody());
596 }
597
598 /**
599 * @return array
600 */
601 public function hierarchicalMenuIsGeneratedDataProvider(): array
602 {
603 return [
604 'ACME Inc' => [
605 1100,
606 [
607 ['title' => 'EN: Welcome', 'link' => 'index.php?id=acme-first'],
608 [
609 'title' => 'EN: Features',
610 'link' => 'index.php?id=1200',
611 'children' => [
612 [
613 'title' => 'EN: Frontend Editing',
614 'link' => 'index.php?id=1210',
615 ],
616 ],
617 ],
618 [
619 'title' => 'EN: Products',
620 'link' => 'index.php?id=1300',
621 'children' => [
622 [
623 'title' => 'EN: Planets',
624 'link' => 'index.php?id=1310',
625 ],
626 [
627 'title' => 'EN: Spaceships',
628 'link' => 'index.php?id=1320',
629 ],
630 [
631 'title' => 'EN: Dark Matter',
632 'link' => 'index.php?id=1330',
633 ],
634 ],
635 ],
636 ['title' => 'EN: ACME in your Region', 'link' => 'index.php?id=1400'],
637 ['title' => 'Internal', 'link' => 'index.php?id=1500'],
638 ['title' => 'About us', 'link' => 'index.php?id=1600'],
639 [
640 'title' => 'Announcements & News',
641 'link' => 'index.php?id=1700',
642 'children' => [
643 [
644 'title' => 'Markets',
645 'link' => 'index.php?id=7110&MP=7100-1700',
646 ],
647 [
648 'title' => 'Products',
649 'link' => 'index.php?id=7120&MP=7100-1700',
650 ],
651 [
652 'title' => 'Partners',
653 'link' => 'index.php?id=7130&MP=7100-1700',
654 ],
655 ],
656 ],
657 ['title' => 'Page not found', 'link' => 'index.php?id=404'],
658 ['title' => 'Our Blog', 'link' => 'index.php?id=2100'],
659 ]
660 ],
661 'ACME Blog' => [
662 2100,
663 [
664 [
665 'title' => 'Authors',
666 'link' => 'index.php?id=2100',
667 'children' => [
668 [
669 'title' => 'John Doe',
670 'link' => 'index.php?id=2110',
671 ],
672 [
673 'title' => 'Jane Doe',
674 'link' => 'index.php?id=2120',
675 ],
676 ],
677 ],
678 1 =>
679 [
680 'title' => 'Announcements & News',
681 'link' => 'index.php?id=2700',
682 'children' => [
683 [
684 'title' => 'Markets',
685 'link' => 'index.php?id=7110&MP=7100-2700',
686 ],
687 [
688 'title' => 'Products',
689 'link' => 'index.php?id=7120&MP=7100-2700',
690 ],
691 [
692 'title' => 'Partners',
693 'link' => 'index.php?id=7130&MP=7100-2700',
694 ],
695 ],
696 ],
697 ['title' => 'ACME Inc', 'link' => 'index.php?id=acme-first'],
698 ]
699 ]
700 ];
701 }
702
703 /**
704 * @param int $sourcePageId
705 * @param array $expectation
706 *
707 * @test
708 * @dataProvider hierarchicalMenuIsGeneratedDataProvider
709 */
710 public function hierarchicalMenuIsGenerated(int $sourcePageId, array $expectation)
711 {
712 $response = $this->executeFrontendRequest(
713 (new InternalRequest())
714 ->withPageId($sourcePageId)
715 ->withInstructions([
716 $this->createHierarchicalMenuProcessorInstruction([
717 'levels' => 2,
718 'entryLevel' => 0,
719 'expandAll' => 1,
720 'includeSpacer' => 1,
721 'titleField' => 'title',
722 'as' => 'results',
723 ])
724 ]),
725 $this->internalRequestContext
726 );
727
728 $json = json_decode((string)$response->getBody(), true);
729 $json = $this->filterMenu($json);
730
731 static::assertSame($expectation, $json);
732 }
733
734 /**
735 * @return array
736 */
737 public function languageMenuIsGeneratedDataProvider(): array
738 {
739 return [
740 'ACME Inc' => [
741 1100,
742 [
743 ['title' => 'Default', 'link' => 'index.php?id=acme-first&L=0'],
744 ['title' => 'French', 'link' => 'index.php?id=acme-first&L=1'],
745 ['title' => 'Franco-Canadian', 'link' => 'index.php?id=acme-first&L=2'],
746 ]
747 ],
748 'ACME Blog' => [
749 2100,
750 [
751 ['title' => 'Default', 'link' => 'index.php?id=2100&L=0'],
752 ['title' => 'French', 'link' => 'index.php?id=2100&L=1'],
753 ['title' => 'Franco-Canadian', 'link' => 'index.php?id=2100&L=2'],
754 ]
755 ]
756 ];
757 }
758
759 /**
760 * @param int $sourcePageId
761 * @param array $expectation
762 *
763 * @test
764 * @dataProvider languageMenuIsGeneratedDataProvider
765 */
766 public function languageMenuIsGenerated(int $sourcePageId, array $expectation)
767 {
768 $response = $this->executeFrontendRequest(
769 (new InternalRequest())
770 ->withPageId($sourcePageId)
771 ->withInstructions([
772 $this->createLanguageMenuProcessorInstruction([
773 'languages' => 'auto',
774 ])
775 ]),
776 $this->internalRequestContext
777 );
778
779 $json = json_decode((string)$response->getBody(), true);
780 $json = $this->filterMenu($json);
781
782 static::assertSame($expectation, $json);
783 }
784 }