[TASK] Prepare Frontend Tests for additional site handling tests
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / Functional / SiteHandling / SlugSiteRequestTest.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\Core\Core\Bootstrap;
19 use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
20 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory;
21 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter;
22 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
23 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequestContext;
24 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\ResponseContent;
25
26 /**
27 * Test case for frontend requests having site handling configured
28 */
29 class SlugSiteRequestTest extends AbstractTestCase
30 {
31 /**
32 * @var string
33 */
34 private $siteTitle = 'A Company that Manufactures Everything Inc';
35
36 /**
37 * @var InternalRequestContext
38 */
39 private $internalRequestContext;
40
41 public static function setUpBeforeClass()
42 {
43 parent::setUpBeforeClass();
44 static::initializeDatabaseSnapshot();
45 }
46
47 public static function tearDownAfterClass()
48 {
49 static::destroyDatabaseSnapshot();
50 parent::tearDownAfterClass();
51 }
52
53 protected function setUp()
54 {
55 parent::setUp();
56
57 // these settings are forwarded to the frontend sub-request as well
58 $this->internalRequestContext = (new InternalRequestContext())
59 ->withGlobalSettings(['TYPO3_CONF_VARS' => static::TYPO3_CONF_VARS]);
60
61 $this->withDatabaseSnapshot(function () {
62 $this->setUpDatabase();
63 });
64 }
65
66 protected function setUpDatabase()
67 {
68 $backendUser = $this->setUpBackendUserFromFixture(1);
69 Bootstrap::initializeLanguageObject();
70
71 $scenarioFile = __DIR__ . '/Fixtures/SlugScenario.yaml';
72 $factory = DataHandlerFactory::fromYamlFile($scenarioFile);
73 $writer = DataHandlerWriter::withBackendUser($backendUser);
74 $writer->invokeFactory($factory);
75 static::failIfArrayIsNotEmpty(
76 $writer->getErrors()
77 );
78
79 $this->setUpFrontendRootPage(
80 1000,
81 [
82 'typo3/sysext/core/Tests/Functional/Fixtures/Frontend/JsonRenderer.typoscript',
83 'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/JsonRenderer.typoscript',
84 ],
85 [
86 'title' => 'ACME Root',
87 'sitetitle' => $this->siteTitle,
88 ]
89 );
90 }
91
92 protected function tearDown()
93 {
94 unset($this->internalRequestContext);
95 parent::tearDown();
96 }
97
98 /**
99 * @return array
100 */
101 public function requestsAreRedirectedWithoutHavingDefaultSiteLanguageDataProvider(): array
102 {
103 $domainPaths = [
104 'https://website.local/',
105 'https://website.local/?',
106 ];
107
108 return $this->wrapInArray(
109 $this->keysFromValues($domainPaths)
110 );
111 }
112
113 /**
114 * @param string $uri
115 *
116 * @test
117 * @dataProvider requestsAreRedirectedWithoutHavingDefaultSiteLanguageDataProvider
118 */
119 public function requestsAreRedirectedWithoutHavingDefaultSiteLanguage(string $uri)
120 {
121 $this->writeSiteConfiguration(
122 'website-local',
123 $this->buildSiteConfiguration(1000, 'https://website.local/')
124 );
125
126 $expectedStatusCode = 307;
127 $expectedHeaders = ['location' => ['https://website.local/welcome']];
128
129 $response = $this->executeFrontendRequest(
130 new InternalRequest($uri),
131 $this->internalRequestContext
132 );
133 static::assertSame($expectedStatusCode, $response->getStatusCode());
134 static::assertSame($expectedHeaders, $response->getHeaders());
135 }
136
137 /**
138 * @return array
139 */
140 public function shortcutsAreRedirectedDataProvider(): array
141 {
142 $domainPaths = [
143 'https://website.local/',
144 'https://website.local/?',
145 'https://website.local/welcome',
146 ];
147
148 return $this->wrapInArray(
149 $this->keysFromValues($domainPaths)
150 );
151 }
152
153 /**
154 * @param string $uri
155 *
156 * @test
157 * @dataProvider shortcutsAreRedirectedDataProvider
158 */
159 public function shortcutsAreRedirectedToDefaultSiteLanguage(string $uri)
160 {
161 $this->writeSiteConfiguration(
162 'website-local',
163 $this->buildSiteConfiguration(1000, 'https://website.local/'),
164 [
165 $this->buildDefaultLanguageConfiguration('EN', '/en-en/'),
166 ]
167 );
168
169 $expectedStatusCode = 307;
170 $expectedHeaders = [
171 'location' => ['https://website.local/en-en/'],
172 ];
173
174 $response = $this->executeFrontendRequest(
175 new InternalRequest($uri),
176 $this->internalRequestContext
177 );
178 static::assertSame($expectedStatusCode, $response->getStatusCode());
179 static::assertSame($expectedHeaders, $response->getHeaders());
180 }
181
182 /**
183 * @param string $uri
184 *
185 * @test
186 * @dataProvider shortcutsAreRedirectedDataProvider
187 */
188 public function shortcutsAreRedirectedAndRenderFirstSubPage(string $uri)
189 {
190 $this->writeSiteConfiguration(
191 'website-local',
192 $this->buildSiteConfiguration(1000, 'https://website.local/'),
193 [
194 $this->buildDefaultLanguageConfiguration('EN', '/en-en/'),
195 ]
196 );
197
198 $expectedStatusCode = 200;
199 $expectedPageTitle = 'EN: Welcome';
200
201 $response = $this->executeFrontendRequest(
202 new InternalRequest($uri),
203 $this->internalRequestContext,
204 true
205 );
206 $responseStructure = ResponseContent::fromString(
207 (string)$response->getBody()
208 );
209
210 static::assertSame(
211 $expectedStatusCode,
212 $response->getStatusCode()
213 );
214 static::assertSame(
215 $this->siteTitle,
216 $responseStructure->getScopePath('template/sitetitle')
217 );
218 static::assertSame(
219 $expectedPageTitle,
220 $responseStructure->getScopePath('page/title')
221 );
222 }
223
224 /**
225 * @test
226 */
227 public function invalidSiteResultsInNotFoundResponse()
228 {
229 $this->writeSiteConfiguration(
230 'website-local',
231 $this->buildSiteConfiguration(1000, 'https://website.local/'),
232 [
233 $this->buildDefaultLanguageConfiguration('EN', '/en-en/'),
234 ],
235 $this->buildErrorHandlingConfiguration('Fluid', [404])
236 );
237
238 $expectedStatusCode = 307;
239 $expectedHeaders = ['location' => ['https://website.local/en-en/welcome']];
240
241 $uri = 'https://website.other/any/invalid/slug';
242 $response = $this->executeFrontendRequest(
243 new InternalRequest($uri),
244 $this->internalRequestContext
245 );
246
247 static::assertSame(
248 $expectedStatusCode,
249 $response->getStatusCode()
250 );
251 static::assertSame(
252 $expectedHeaders,
253 $response->getHeaders()
254 );
255 // @todo Expected page not found response (404) instead
256 // static::assertContains(
257 // 'message: The requested page does not exist',
258 // (string)$response->getBody()
259 // );
260 }
261
262 /**
263 * @test
264 */
265 public function invalidSlugOutsideSiteLanguageResultsInNotFoundResponse()
266 {
267 $this->writeSiteConfiguration(
268 'website-local',
269 $this->buildSiteConfiguration(1000, 'https://website.local/'),
270 [
271 $this->buildDefaultLanguageConfiguration('EN', '/en-en/')
272 ],
273 $this->buildErrorHandlingConfiguration('Fluid', [404])
274 );
275
276 $expectedStatusCode = 307;
277 $expectedHeaders = ['location' => ['https://website.local/en-en/']];
278
279 $uri = 'https://website.local/any/invalid/slug';
280 $response = $this->executeFrontendRequest(
281 new InternalRequest($uri),
282 $this->internalRequestContext
283 );
284
285 static::assertSame(
286 $expectedStatusCode,
287 $response->getStatusCode()
288 );
289 static::assertSame(
290 $expectedHeaders,
291 $response->getHeaders()
292 );
293 // @todo Expected page not found response (404) instead
294 // static::assertContains(
295 // 'message: The requested page does not exist',
296 // (string)$response->getBody()
297 // );
298 }
299 /**
300 * @test
301 */
302 public function invalidSlugInsideSiteLanguageResultsInNotFoundResponse()
303 {
304 $this->writeSiteConfiguration(
305 'website-local',
306 $this->buildSiteConfiguration(1000, 'https://website.local/'),
307 [
308 $this->buildDefaultLanguageConfiguration('EN', '/en-en/')
309 ],
310 $this->buildErrorHandlingConfiguration('Fluid', [404])
311 );
312
313 $uri = 'https://website.local/en-en/any/invalid/slug';
314 $response = $this->executeFrontendRequest(
315 new InternalRequest($uri),
316 $this->internalRequestContext
317 );
318
319 static::assertSame(
320 404,
321 $response->getStatusCode()
322 );
323 static::assertContains(
324 'message: The requested page does not exist',
325 (string)$response->getBody()
326 );
327 }
328
329 /**
330 * @return array
331 */
332 public function pageIsRenderedWithPathsDataProvider(): array
333 {
334 $domainPaths = [
335 'https://website.local/en-en/welcome',
336 'https://website.local/fr-fr/bienvenue',
337 'https://website.local/fr-ca/bienvenue',
338 ];
339
340 return array_map(
341 function (string $uri) {
342 if (strpos($uri, '/fr-fr/') !== false) {
343 $expectedPageTitle = 'FR: Welcome';
344 } elseif (strpos($uri, '/fr-ca/') !== false) {
345 $expectedPageTitle = 'FR-CA: Welcome';
346 } else {
347 $expectedPageTitle = 'EN: Welcome';
348 }
349 return [$uri, $expectedPageTitle];
350 },
351 $this->keysFromValues($domainPaths)
352 );
353 }
354
355 /**
356 * @param string $uri
357 * @param string $expectedPageTitle
358 *
359 * @test
360 * @dataProvider pageIsRenderedWithPathsDataProvider
361 */
362 public function pageIsRenderedWithPaths(string $uri, string $expectedPageTitle)
363 {
364 $this->writeSiteConfiguration(
365 'website-local',
366 $this->buildSiteConfiguration(1000, 'https://website.local/'),
367 [
368 $this->buildDefaultLanguageConfiguration('EN', '/en-en/'),
369 $this->buildLanguageConfiguration('FR', '/fr-fr/', ['EN']),
370 $this->buildLanguageConfiguration('FR-CA', '/fr-ca/', ['FR', 'EN']),
371 ]
372 );
373
374 $response = $this->executeFrontendRequest(
375 new InternalRequest($uri),
376 $this->internalRequestContext
377 );
378 $responseStructure = ResponseContent::fromString(
379 (string)$response->getBody()
380 );
381
382 static::assertSame(
383 200,
384 $response->getStatusCode()
385 );
386 static::assertSame(
387 $this->siteTitle,
388 $responseStructure->getScopePath('template/sitetitle')
389 );
390 static::assertSame(
391 $expectedPageTitle,
392 $responseStructure->getScopePath('page/title')
393 );
394 }
395
396 /**
397 * @return array
398 */
399 public function pageIsRenderedWithDomainsDataProvider(): array
400 {
401 $domainPaths = [
402 'https://website.us/welcome',
403 'https://website.fr/bienvenue',
404 'https://website.ca/bienvenue',
405 ];
406
407 return array_map(
408 function (string $uri) {
409 if (strpos($uri, '.fr/') !== false) {
410 $expectedPageTitle = 'FR: Welcome';
411 } elseif (strpos($uri, '.ca/') !== false) {
412 $expectedPageTitle = 'FR-CA: Welcome';
413 } else {
414 $expectedPageTitle = 'EN: Welcome';
415 }
416 return [$uri, $expectedPageTitle];
417 },
418 $this->keysFromValues($domainPaths)
419 );
420 }
421
422 /**
423 * @param string $uri
424 * @param string $expectedPageTitle
425 *
426 * @test
427 * @dataProvider pageIsRenderedWithDomainsDataProvider
428 */
429 public function pageIsRenderedWithDomains(string $uri, string $expectedPageTitle)
430 {
431 $this->writeSiteConfiguration(
432 'website-local',
433 $this->buildSiteConfiguration(1000, 'https://website.local/'),
434 [
435 $this->buildDefaultLanguageConfiguration('EN', 'https://website.us/'),
436 $this->buildLanguageConfiguration('FR', 'https://website.fr/', ['EN']),
437 $this->buildLanguageConfiguration('FR-CA', 'https://website.ca/', ['FR', 'EN']),
438 ]
439 );
440
441 $response = $this->executeFrontendRequest(
442 new InternalRequest($uri),
443 $this->internalRequestContext
444 );
445 $responseStructure = ResponseContent::fromString(
446 (string)$response->getBody()
447 );
448
449 static::assertSame(
450 200,
451 $response->getStatusCode()
452 );
453 static::assertSame(
454 $this->siteTitle,
455 $responseStructure->getScopePath('template/sitetitle')
456 );
457 static::assertSame(
458 $expectedPageTitle,
459 $responseStructure->getScopePath('page/title')
460 );
461 }
462
463 /**
464 * @return array
465 */
466 public function restrictedPageIsRenderedDataProvider(): array
467 {
468 $instructions = [
469 // frontend user 1
470 ['https://website.local/my-acme/whitepapers', 1, 'Whitepapers'],
471 ['https://website.local/my-acme/whitepapers/products', 1, 'Products'],
472 ['https://website.local/my-acme/whitepapers/solutions', 1, 'Solutions'],
473 // frontend user 2
474 ['https://website.local/my-acme/whitepapers', 2, 'Whitepapers'],
475 ['https://website.local/my-acme/whitepapers/products', 2, 'Products'],
476 ['https://website.local/my-acme/whitepapers/research', 2, 'Research'],
477 ['https://website.local/my-acme/forecasts', 2, 'Forecasts'],
478 ['https://website.local/my-acme/forecasts/current-year', 2, 'Current Year'],
479 // frontend user 3
480 ['https://website.local/my-acme/whitepapers', 3, 'Whitepapers'],
481 ['https://website.local/my-acme/whitepapers/products', 3, 'Products'],
482 ['https://website.local/my-acme/whitepapers/solutions', 3, 'Solutions'],
483 ['https://website.local/my-acme/whitepapers/research', 3, 'Research'],
484 ['https://website.local/my-acme/forecasts', 3, 'Forecasts'],
485 ['https://website.local/my-acme/forecasts/current-year', 3, 'Current Year'],
486 ];
487
488 return $this->keysFromTemplate($instructions, '%1$s (user:%2$s)');
489 }
490
491 /**
492 * @param string $uri
493 * @param int $frontendUserId
494 * @param string $expectedPageTitle
495 *
496 * @test
497 * @dataProvider restrictedPageIsRenderedDataProvider
498 */
499 public function restrictedPageIsRendered(string $uri, int $frontendUserId, string $expectedPageTitle)
500 {
501 $this->writeSiteConfiguration(
502 'website-local',
503 $this->buildSiteConfiguration(1000, 'https://website.local/')
504 );
505
506 $response = $this->executeFrontendRequest(
507 new InternalRequest($uri),
508 $this->internalRequestContext
509 ->withFrontendUserId($frontendUserId)
510 );
511 $responseStructure = ResponseContent::fromString(
512 (string)$response->getBody()
513 );
514
515 static::assertSame(
516 200,
517 $response->getStatusCode()
518 );
519 static::assertSame(
520 $this->siteTitle,
521 $responseStructure->getScopePath('template/sitetitle')
522 );
523 static::assertSame(
524 $expectedPageTitle,
525 $responseStructure->getScopePath('page/title')
526 );
527 }
528
529 /**
530 * @return array
531 */
532 public function restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorDataProvider(): array
533 {
534 $instructions = [
535 // no frontend user given
536 ['https://website.local/my-acme/whitepapers', 0],
537 // ['https://website.local/my-acme/whitepapers/products', 0], // @todo extendToSubpages currently missing
538 ['https://website.local/my-acme/whitepapers/solutions', 0],
539 ['https://website.local/my-acme/whitepapers/research', 0],
540 ['https://website.local/my-acme/forecasts', 0],
541 // ['https://website.local/my-acme/forecasts/current-year', 0], // @todo extendToSubpages currently missing
542 // frontend user 1
543 ['https://website.local/my-acme/whitepapers/research', 1],
544 ['https://website.local/my-acme/forecasts', 1],
545 // ['https://website.local/my-acme/forecasts/current-year', 1], // @todo extendToSubpages currently missing
546 // frontend user 2
547 ['https://website.local/my-acme/whitepapers/solutions', 2],
548 ];
549
550 return $this->keysFromTemplate($instructions, '%1$s (user:%2$s)');
551 }
552
553 /**
554 * @param string $uri
555 * @param int $frontendUserId
556 *
557 * @test
558 * @dataProvider restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorDataProvider
559 */
560 public function restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorWithoutHavingErrorHandling(string $uri, int $frontendUserId)
561 {
562 $this->writeSiteConfiguration(
563 'website-local',
564 $this->buildSiteConfiguration(1000, 'https://website.local/')
565 );
566
567 $response = $this->executeFrontendRequest(
568 new InternalRequest($uri),
569 $this->internalRequestContext
570 ->withFrontendUserId($frontendUserId)
571 );
572
573 static::assertSame(
574 403,
575 $response->getStatusCode()
576 );
577 static::assertThat(
578 (string)$response->getBody(),
579 static::logicalOr(
580 static::stringContains('Reason: ID was not an accessible page'),
581 static::stringContains('Reason: Subsection was found and not accessible')
582 )
583 );
584 }
585
586 /**
587 * @param string $uri
588 * @param int $frontendUserId
589 *
590 * @test
591 * @dataProvider restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorDataProvider
592 */
593 public function restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorWithHavingFluidErrorHandling(string $uri, int $frontendUserId)
594 {
595 $this->writeSiteConfiguration(
596 'website-local',
597 $this->buildSiteConfiguration(1000, 'https://website.local/'),
598 [],
599 $this->buildErrorHandlingConfiguration('Fluid', [403])
600 );
601
602 $response = $this->executeFrontendRequest(
603 new InternalRequest($uri),
604 $this->internalRequestContext
605 ->withFrontendUserId($frontendUserId)
606 );
607
608 static::assertSame(
609 403,
610 $response->getStatusCode()
611 );
612 static::assertContains(
613 'reasons: code,fe_group',
614 (string)$response->getBody()
615 );
616 static::assertThat(
617 (string)$response->getBody(),
618 static::logicalOr(
619 static::stringContains('message: ID was not an accessible page'),
620 static::stringContains('message: Subsection was found and not accessible')
621 )
622 );
623 }
624
625 /**
626 * @param string $uri
627 * @param int $frontendUserId
628 *
629 * @test
630 * @dataProvider restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorDataProvider
631 * @todo Response body cannot be asserted since PageContentErrorHandler::handlePageError executes request via HTTP (not internally)
632 */
633 public function restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorWithHavingPageErrorHandling(string $uri, int $frontendUserId)
634 {
635 $this->markTestSkipped('Skipped until PageContentErrorHandler::handlePageError does not use HTTP anymore');
636
637 $this->writeSiteConfiguration(
638 'website-local',
639 $this->buildSiteConfiguration(1000, 'https://website.local/'),
640 [],
641 $this->buildErrorHandlingConfiguration('Page', [403])
642 );
643
644 $response = $this->executeFrontendRequest(
645 new InternalRequest($uri),
646 $this->internalRequestContext
647 ->withFrontendUserId($frontendUserId)
648 );
649
650 static::assertSame(
651 403,
652 $response->getStatusCode()
653 );
654 }
655
656 /**
657 * @param string $uri
658 * @param int $frontendUserId
659 *
660 * @test
661 * @dataProvider restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorDataProvider
662 */
663 public function restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorWithHavingPhpErrorHandling(string $uri, int $frontendUserId)
664 {
665 $this->writeSiteConfiguration(
666 'website-local',
667 $this->buildSiteConfiguration(1000, 'https://website.local/'),
668 [],
669 $this->buildErrorHandlingConfiguration('PHP', [403])
670 );
671
672 $response = $this->executeFrontendRequest(
673 new InternalRequest($uri),
674 $this->internalRequestContext
675 ->withFrontendUserId($frontendUserId)
676 );
677 $json = json_decode((string)$response->getBody(), true);
678
679 static::assertSame(
680 403,
681 $response->getStatusCode()
682 );
683 static::assertThat(
684 $json['message'] ?? null,
685 static::logicalOr(
686 static::identicalTo('ID was not an accessible page'),
687 static::identicalTo('Subsection was found and not accessible')
688 )
689 );
690 }
691
692 /**
693 * @return array
694 */
695 public function pageRenderingStopsWithInvalidCacheHashDataProvider(): array
696 {
697 $domainPaths = [
698 'https://website.local/',
699 ];
700
701 $queries = [
702 '',
703 'welcome',
704 ];
705
706 $customQueries = [
707 '?testing[value]=1',
708 '?testing[value]=1&cHash=',
709 '?testing[value]=1&cHash=WRONG',
710 ];
711
712 return $this->wrapInArray(
713 $this->keysFromValues(
714 $this->meltStrings([$domainPaths, $queries, $customQueries])
715 )
716 );
717 }
718
719 /**
720 * @param string $uri
721 *
722 * @test
723 * @dataProvider pageRenderingStopsWithInvalidCacheHashDataProvider
724 */
725 public function pageRequestThrowsExceptionWithInvalidCacheHashWithoutHavingErrorHandling(string $uri)
726 {
727 $this->writeSiteConfiguration(
728 'website-local',
729 $this->buildSiteConfiguration(1000, 'https://website.local/')
730 );
731
732 $this->expectExceptionCode(1518472189);
733 $this->expectException(PageNotFoundException::class);
734
735 $this->executeFrontendRequest(
736 new InternalRequest($uri),
737 $this->internalRequestContext
738 );
739 }
740
741 /**
742 * @param string $uri
743 *
744 * @test
745 * @dataProvider pageRenderingStopsWithInvalidCacheHashDataProvider
746 */
747 public function pageRequestSendsNotFoundResponseWithInvalidCacheHash(string $uri)
748 {
749 $response = $this->executeFrontendRequest(
750 new InternalRequest($uri),
751 $this->internalRequestContext->withMergedGlobalSettings([
752 'TYPO3_CONF_VARS' => [
753 'FE' => [
754 'pageNotFound_handling' => 'READFILE:typo3/sysext/core/Tests/Functional/Fixtures/Frontend/PageError.txt',
755 ]
756 ]
757 ])
758 );
759
760 static::assertSame(
761 404,
762 $response->getStatusCode()
763 );
764 static::assertThat(
765 (string)$response->getBody(),
766 static::logicalOr(
767 static::stringContains('reason: Request parameters could not be validated (&amp;cHash empty)'),
768 static::stringContains('reason: Request parameters could not be validated (&amp;cHash comparison failed)')
769 )
770 );
771 }
772
773 /**
774 * @param string $uri
775 *
776 * @test
777 * @dataProvider pageRenderingStopsWithInvalidCacheHashDataProvider
778 */
779 public function pageRequestSendsNotFoundResponseWithInvalidCacheHashWithHavingFluidErrorHandling(string $uri)
780 {
781 $this->writeSiteConfiguration(
782 'website-local',
783 $this->buildSiteConfiguration(1000, 'https://website.local/'),
784 [],
785 $this->buildErrorHandlingConfiguration('Fluid', [404])
786 );
787
788 $response = $this->executeFrontendRequest(
789 new InternalRequest($uri),
790 $this->internalRequestContext
791 );
792
793 static::assertSame(
794 404,
795 $response->getStatusCode()
796 );
797 static::assertThat(
798 (string)$response->getBody(),
799 static::logicalOr(
800 static::stringContains('message: Request parameters could not be validated (&amp;cHash empty)'),
801 static::stringContains('message: Request parameters could not be validated (&amp;cHash comparison failed)')
802 )
803 );
804 }
805
806 /**
807 * @param string $uri
808 *
809 * @test
810 * @dataProvider pageRenderingStopsWithInvalidCacheHashDataProvider
811 * @todo Response body cannot be asserted since PageContentErrorHandler::handlePageError executes request via HTTP (not internally)
812 */
813 public function pageRequestSendsNotFoundResponseWithInvalidCacheHashWithHavingPageErrorHandling(string $uri)
814 {
815 $this->markTestSkipped('Skipped until PageContentErrorHandler::handlePageError does not use HTTP anymore');
816
817 $this->writeSiteConfiguration(
818 'website-local',
819 $this->buildSiteConfiguration(1000, 'https://website.local/'),
820 [],
821 $this->buildErrorHandlingConfiguration('Page', [404])
822 );
823
824 $response = $this->executeFrontendRequest(
825 new InternalRequest($uri),
826 $this->internalRequestContext
827 );
828
829 static::assertSame(
830 404,
831 $response->getStatusCode()
832 );
833 }
834
835 /**
836 * @param string $uri
837 *
838 * @test
839 * @dataProvider pageRenderingStopsWithInvalidCacheHashDataProvider
840 */
841 public function pageRequestSendsNotFoundResponseWithInvalidCacheHashWithHavingPhpErrorHandling(string $uri)
842 {
843 $this->writeSiteConfiguration(
844 'website-local',
845 $this->buildSiteConfiguration(1000, 'https://website.local/'),
846 [],
847 $this->buildErrorHandlingConfiguration('PHP', [404])
848 );
849
850 $response = $this->executeFrontendRequest(
851 new InternalRequest($uri),
852 $this->internalRequestContext
853 );
854 $json = json_decode((string)$response->getBody(), true);
855
856 static::assertSame(
857 404,
858 $response->getStatusCode()
859 );
860 static::assertThat(
861 $json['message'] ?? null,
862 static::logicalOr(
863 static::identicalTo('Request parameters could not be validated (&cHash empty)'),
864 static::identicalTo('Request parameters could not be validated (&cHash comparison failed)')
865 )
866 );
867 }
868
869 /**
870 * @return array
871 */
872 public function pageIsRenderedWithValidCacheHashDataProvider(): array
873 {
874 $domainPaths = [
875 'https://website.local/',
876 ];
877
878 // cHash has been calculated with encryption key set to
879 // '4408d27a916d51e624b69af3554f516dbab61037a9f7b9fd6f81b4d3bedeccb6'
880 $queries = [
881 // @todo Currently fails since cHash is verified after(!) redirect to page 1100
882 // '?cHash=7d1f13fa91159dac7feb3c824936b39d',
883 // '?cHash=7d1f13fa91159dac7feb3c824936b39d',
884 'welcome?cHash=f42b850e435f0cedd366f5db749fc1af',
885 ];
886
887 $customQueries = [
888 '&testing[value]=1',
889 ];
890
891 $dataSet = $this->wrapInArray(
892 $this->keysFromValues(
893 $this->meltStrings([$domainPaths, $queries, $customQueries])
894 )
895 );
896
897 return $dataSet;
898 }
899
900 /**
901 * @param string $uri
902 *
903 * @test
904 * @dataProvider pageIsRenderedWithValidCacheHashDataProvider
905 */
906 public function pageIsRenderedWithValidCacheHash($uri)
907 {
908 $this->writeSiteConfiguration(
909 'website-local',
910 $this->buildSiteConfiguration(1000, 'https://website.local/')
911 );
912
913 $response = $this->executeFrontendRequest(
914 new InternalRequest($uri),
915 $this->internalRequestContext
916 );
917 $responseStructure = ResponseContent::fromString(
918 (string)$response->getBody()
919 );
920 static::assertSame(
921 '1',
922 $responseStructure->getScopePath('getpost/testing.value')
923 );
924 }
925 }