[TASK] Prepare Frontend Tests for additional site handling tests
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / Functional / SiteHandling / SiteRequestTest.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 SiteRequestTest 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/PlainScenario.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 shortcutsAreRedirectedDataProvider(): array
102 {
103 $domainPaths = [
104 // @todo Implicit strict mode handling when calling non-existent site
105 // '/',
106 // 'https://localhost/',
107 'https://website.local/',
108 ];
109
110 $queries = [
111 '',
112 ];
113
114 return $this->wrapInArray(
115 $this->keysFromValues(
116 $this->meltStrings([$domainPaths, $queries])
117 )
118 );
119 }
120
121 /**
122 * @param string $uri
123 *
124 * @test
125 * @dataProvider shortcutsAreRedirectedDataProvider
126 */
127 public function shortcutsAreRedirectedToFirstSubPage(string $uri)
128 {
129 $this->writeSiteConfiguration(
130 'website-local',
131 $this->buildSiteConfiguration(1000, 'https://website.local/'),
132 [
133 $this->buildDefaultLanguageConfiguration('EN', '/en-en/'),
134 ]
135 );
136
137 $expectedStatusCode = 307;
138 $expectedHeaders = ['location' => ['https://website.local/en-en/']];
139
140 $response = $this->executeFrontendRequest(
141 new InternalRequest($uri),
142 $this->internalRequestContext
143 );
144 static::assertSame($expectedStatusCode, $response->getStatusCode());
145 static::assertSame($expectedHeaders, $response->getHeaders());
146 }
147
148 /**
149 * @param string $uri
150 *
151 * @test
152 * @dataProvider shortcutsAreRedirectedDataProvider
153 */
154 public function shortcutsAreRedirectedAndRenderFirstSubPage(string $uri)
155 {
156 $this->writeSiteConfiguration(
157 'website-local',
158 $this->buildSiteConfiguration(1000, 'https://website.local/'),
159 [
160 $this->buildDefaultLanguageConfiguration('EN', '/en-en/'),
161 ]
162 );
163
164 $expectedStatusCode = 200;
165 $expectedPageTitle = 'EN: Welcome';
166
167 $response = $this->executeFrontendRequest(
168 new InternalRequest($uri),
169 $this->internalRequestContext,
170 true
171 );
172 $responseStructure = ResponseContent::fromString(
173 (string)$response->getBody()
174 );
175
176 static::assertSame(
177 $expectedStatusCode,
178 $response->getStatusCode()
179 );
180 static::assertSame(
181 $this->siteTitle,
182 $responseStructure->getScopePath('template/sitetitle')
183 );
184 static::assertSame(
185 $expectedPageTitle,
186 $responseStructure->getScopePath('page/title')
187 );
188 }
189
190 /**
191 * @return array
192 */
193 public function pageIsRenderedWithPathsDataProvider(): array
194 {
195 $domainPaths = [
196 // @todo currently base needs to be defined with domain
197 // '/',
198 'https://website.local/',
199 ];
200
201 $languagePaths = [
202 'en-en/',
203 'fr-fr/',
204 'fr-ca/',
205 ];
206
207 $queries = [
208 '?id=1100',
209 ];
210
211 return array_map(
212 function (string $uri) {
213 if (strpos($uri, '/fr-fr/') !== false) {
214 $expectedPageTitle = 'FR: Welcome';
215 } elseif (strpos($uri, '/fr-ca/') !== false) {
216 $expectedPageTitle = 'FR-CA: Welcome';
217 } else {
218 $expectedPageTitle = 'EN: Welcome';
219 }
220 return [$uri, $expectedPageTitle];
221 },
222 $this->keysFromValues(
223 $this->meltStrings([$domainPaths, $languagePaths, $queries])
224 )
225 );
226 }
227
228 /**
229 * @param string $uri
230 * @param string $expectedPageTitle
231 *
232 * @test
233 * @dataProvider pageIsRenderedWithPathsDataProvider
234 */
235 public function pageIsRenderedWithPaths(string $uri, string $expectedPageTitle)
236 {
237 $this->writeSiteConfiguration(
238 'website-local',
239 $this->buildSiteConfiguration(1000, 'https://website.local/'),
240 [
241 $this->buildDefaultLanguageConfiguration('EN', '/en-en/'),
242 $this->buildLanguageConfiguration('FR', '/fr-fr/', ['EN']),
243 $this->buildLanguageConfiguration('FR-CA', '/fr-ca/', ['FR', 'EN']),
244 ]
245 );
246
247 $response = $this->executeFrontendRequest(
248 new InternalRequest($uri),
249 $this->internalRequestContext
250 );
251 $responseStructure = ResponseContent::fromString(
252 (string)$response->getBody()
253 );
254
255 static::assertSame(
256 200,
257 $response->getStatusCode()
258 );
259 static::assertSame(
260 $this->siteTitle,
261 $responseStructure->getScopePath('template/sitetitle')
262 );
263 static::assertSame(
264 $expectedPageTitle,
265 $responseStructure->getScopePath('page/title')
266 );
267 }
268
269 /**
270 * @return array
271 */
272 public function pageIsRenderedWithDomainsDataProvider(): array
273 {
274 $domainPaths = [
275 // @todo: This turns into a redirect to the default language (".us") making this function obsolete
276 // 'https://website.local/',
277 'https://website.us/',
278 'https://website.fr/',
279 // Explicitly testing umlaut domains
280 'https://wäbsite.ca/',
281 // @todo Implicit strict mode handling when calling non-existent site
282 // 'https://website.other/',
283 ];
284
285 $queries = [
286 '?id=1100',
287 ];
288
289 return array_map(
290 function (string $uri) {
291 if (strpos($uri, '.fr/') !== false) {
292 $expectedPageTitle = 'FR: Welcome';
293 } elseif (strpos($uri, '.ca/') !== false) {
294 $expectedPageTitle = 'FR-CA: Welcome';
295 } else {
296 $expectedPageTitle = 'EN: Welcome';
297 }
298 return [$uri, $expectedPageTitle];
299 },
300 $this->keysFromValues(
301 $this->meltStrings([$domainPaths, $queries])
302 )
303 );
304 }
305
306 /**
307 * @param string $uri
308 * @param string $expectedPageTitle
309 *
310 * @test
311 * @dataProvider pageIsRenderedWithDomainsDataProvider
312 */
313 public function pageIsRenderedWithDomains(string $uri, string $expectedPageTitle)
314 {
315 $this->writeSiteConfiguration(
316 'website-local',
317 $this->buildSiteConfiguration(1000, 'https://website.local/'),
318 [
319 $this->buildDefaultLanguageConfiguration('EN', 'https://website.us/'),
320 $this->buildLanguageConfiguration('FR', 'https://website.fr/', ['EN']),
321 $this->buildLanguageConfiguration('FR-CA', 'https://wäbsite.ca/', ['FR', 'EN']),
322 ]
323 );
324
325 $response = $this->executeFrontendRequest(
326 new InternalRequest($uri),
327 $this->internalRequestContext
328 );
329 $responseStructure = ResponseContent::fromString(
330 (string)$response->getBody()
331 );
332
333 static::assertSame(
334 200,
335 $response->getStatusCode()
336 );
337 static::assertSame(
338 $this->siteTitle,
339 $responseStructure->getScopePath('template/sitetitle')
340 );
341 static::assertSame(
342 $expectedPageTitle,
343 $responseStructure->getScopePath('page/title')
344 );
345 }
346
347 /**
348 * @return array
349 */
350 public function restrictedPageIsRenderedDataProvider(): array
351 {
352 $instructions = [
353 // frontend user 1
354 ['https://website.local/?id=1510', 1, 'Whitepapers'],
355 ['https://website.local/?id=1511', 1, 'Products'],
356 ['https://website.local/?id=1512', 1, 'Solutions'],
357 // frontend user 2
358 ['https://website.local/?id=1510', 2, 'Whitepapers'],
359 ['https://website.local/?id=1511', 2, 'Products'],
360 ['https://website.local/?id=1515', 2, 'Research'],
361 ['https://website.local/?id=1520', 2, 'Forecasts'],
362 ['https://website.local/?id=1521', 2, 'Current Year'],
363 // frontend user 3
364 ['https://website.local/?id=1510', 3, 'Whitepapers'],
365 ['https://website.local/?id=1511', 3, 'Products'],
366 ['https://website.local/?id=1512', 3, 'Solutions'],
367 ['https://website.local/?id=1515', 3, 'Research'],
368 ['https://website.local/?id=1520', 3, 'Forecasts'],
369 ['https://website.local/?id=1521', 3, 'Current Year'],
370 ];
371
372 return $this->keysFromTemplate($instructions, '%1$s (user:%2$s)');
373 }
374
375 /**
376 * @param string $uri
377 * @param int $frontendUserId
378 * @param string $expectedPageTitle
379 *
380 * @test
381 * @dataProvider restrictedPageIsRenderedDataProvider
382 */
383 public function restrictedPageIsRendered(string $uri, int $frontendUserId, string $expectedPageTitle)
384 {
385 $this->writeSiteConfiguration(
386 'website-local',
387 $this->buildSiteConfiguration(1000, 'https://website.local/')
388 );
389
390 $response = $this->executeFrontendRequest(
391 new InternalRequest($uri),
392 $this->internalRequestContext
393 ->withFrontendUserId($frontendUserId)
394 );
395 $responseStructure = ResponseContent::fromString(
396 (string)$response->getBody()
397 );
398
399 static::assertSame(
400 200,
401 $response->getStatusCode()
402 );
403 static::assertSame(
404 $this->siteTitle,
405 $responseStructure->getScopePath('template/sitetitle')
406 );
407 static::assertSame(
408 $expectedPageTitle,
409 $responseStructure->getScopePath('page/title')
410 );
411 }
412
413 /**
414 * @return array
415 */
416 public function restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorDataProvider(): array
417 {
418 $instructions = [
419 // no frontend user given
420 ['https://website.local/?id=1510', 0],
421 ['https://website.local/?id=1511', 0],
422 ['https://website.local/?id=1512', 0],
423 ['https://website.local/?id=1515', 0],
424 ['https://website.local/?id=1520', 0],
425 ['https://website.local/?id=1521', 0],
426 // frontend user 1
427 ['https://website.local/?id=1515', 1],
428 ['https://website.local/?id=1520', 1],
429 ['https://website.local/?id=1521', 1],
430 // frontend user 2
431 ['https://website.local/?id=1512', 2],
432 ];
433
434 return $this->keysFromTemplate($instructions, '%1$s (user:%2$s)');
435 }
436
437 /**
438 * @param string $uri
439 * @param int $frontendUserId
440 *
441 * @test
442 * @dataProvider restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorDataProvider
443 */
444 public function restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorWithoutHavingErrorHandling(string $uri, int $frontendUserId)
445 {
446 $this->writeSiteConfiguration(
447 'website-local',
448 $this->buildSiteConfiguration(1000, 'https://website.local/')
449 );
450
451 $response = $this->executeFrontendRequest(
452 new InternalRequest($uri),
453 $this->internalRequestContext
454 ->withFrontendUserId($frontendUserId)
455 );
456
457 static::assertSame(
458 403,
459 $response->getStatusCode()
460 );
461 static::assertThat(
462 (string)$response->getBody(),
463 static::logicalOr(
464 static::stringContains('Reason: ID was not an accessible page'),
465 static::stringContains('Reason: Subsection was found and not accessible')
466 )
467 );
468 }
469
470 /**
471 * @param string $uri
472 * @param int $frontendUserId
473 *
474 * @test
475 * @dataProvider restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorDataProvider
476 */
477 public function restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorWithHavingFluidErrorHandling(string $uri, int $frontendUserId)
478 {
479 $this->writeSiteConfiguration(
480 'website-local',
481 $this->buildSiteConfiguration(1000, 'https://website.local/'),
482 [],
483 $this->buildErrorHandlingConfiguration('Fluid', [403])
484 );
485
486 $response = $this->executeFrontendRequest(
487 new InternalRequest($uri),
488 $this->internalRequestContext
489 ->withFrontendUserId($frontendUserId)
490 );
491
492 static::assertSame(
493 403,
494 $response->getStatusCode()
495 );
496 static::assertContains(
497 'reasons: code,fe_group',
498 (string)$response->getBody()
499 );
500 static::assertThat(
501 (string)$response->getBody(),
502 static::logicalOr(
503 static::stringContains('message: ID was not an accessible page'),
504 static::stringContains('message: Subsection was found and not accessible')
505 )
506 );
507 }
508
509 /**
510 * @param string $uri
511 * @param int $frontendUserId
512 *
513 * @test
514 * @dataProvider restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorDataProvider
515 * @todo Response body cannot be asserted since PageContentErrorHandler::handlePageError executes request via HTTP (not internally)
516 */
517 public function restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorWithHavingPageErrorHandling(string $uri, int $frontendUserId)
518 {
519 $this->markTestSkipped('Skipped until PageContentErrorHandler::handlePageError does not use HTTP anymore');
520
521 $this->writeSiteConfiguration(
522 'website-local',
523 $this->buildSiteConfiguration(1000, 'https://website.local/'),
524 [],
525 $this->buildErrorHandlingConfiguration('Page', [403])
526 );
527
528 $response = $this->executeFrontendRequest(
529 new InternalRequest($uri),
530 $this->internalRequestContext
531 ->withFrontendUserId($frontendUserId)
532 );
533
534 static::assertSame(
535 403,
536 $response->getStatusCode()
537 );
538 }
539
540 /**
541 * @param string $uri
542 * @param int $frontendUserId
543 *
544 * @test
545 * @dataProvider restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorDataProvider
546 */
547 public function restrictedPageSendsForbiddenResponseWithUnauthorizedVisitorWithHavingPhpErrorHandling(string $uri, int $frontendUserId)
548 {
549 $this->writeSiteConfiguration(
550 'website-local',
551 $this->buildSiteConfiguration(1000, 'https://website.local/'),
552 [],
553 $this->buildErrorHandlingConfiguration('PHP', [403])
554 );
555
556 $response = $this->executeFrontendRequest(
557 new InternalRequest($uri),
558 $this->internalRequestContext
559 ->withFrontendUserId($frontendUserId)
560 );
561 $json = json_decode((string)$response->getBody(), true);
562
563 static::assertSame(
564 403,
565 $response->getStatusCode()
566 );
567 static::assertThat(
568 $json['message'] ?? null,
569 static::logicalOr(
570 static::identicalTo('ID was not an accessible page'),
571 static::identicalTo('Subsection was found and not accessible')
572 )
573 );
574 }
575
576 /**
577 * @return array
578 */
579 public function pageRenderingStopsWithInvalidCacheHashDataProvider(): array
580 {
581 $domainPaths = [
582 'https://website.local/',
583 ];
584
585 $queries = [
586 '?',
587 '?id=1000',
588 '?id=1100',
589 ];
590
591 $customQueries = [
592 '&testing[value]=1',
593 '&testing[value]=1&cHash=',
594 '&testing[value]=1&cHash=WRONG',
595 ];
596
597 return $this->wrapInArray(
598 $this->keysFromValues(
599 $this->meltStrings([$domainPaths, $queries, $customQueries])
600 )
601 );
602 }
603
604 /**
605 * @param string $uri
606 *
607 * @test
608 * @dataProvider pageRenderingStopsWithInvalidCacheHashDataProvider
609 */
610 public function pageRequestThrowsExceptionWithInvalidCacheHashWithoutHavingErrorHandling(string $uri)
611 {
612 $this->writeSiteConfiguration(
613 'website-local',
614 $this->buildSiteConfiguration(1000, 'https://website.local/')
615 );
616
617 $this->expectExceptionCode(1518472189);
618 $this->expectException(PageNotFoundException::class);
619
620 $this->executeFrontendRequest(
621 new InternalRequest($uri),
622 $this->internalRequestContext
623 );
624 }
625
626 /**
627 * @param string $uri
628 *
629 * @test
630 * @dataProvider pageRenderingStopsWithInvalidCacheHashDataProvider
631 */
632 public function pageRequestSendsNotFoundResponseWithInvalidCacheHash(string $uri)
633 {
634 $response = $this->executeFrontendRequest(
635 new InternalRequest($uri),
636 $this->internalRequestContext->withMergedGlobalSettings([
637 'TYPO3_CONF_VARS' => [
638 'FE' => [
639 'pageNotFound_handling' => 'READFILE:typo3/sysext/core/Tests/Functional/Fixtures/Frontend/PageError.txt',
640 ]
641 ]
642 ])
643 );
644
645 static::assertSame(
646 404,
647 $response->getStatusCode()
648 );
649 static::assertThat(
650 (string)$response->getBody(),
651 static::logicalOr(
652 static::stringContains('reason: Request parameters could not be validated (&amp;cHash empty)'),
653 static::stringContains('reason: Request parameters could not be validated (&amp;cHash comparison failed)')
654 )
655 );
656 }
657
658 /**
659 * @param string $uri
660 *
661 * @test
662 * @dataProvider pageRenderingStopsWithInvalidCacheHashDataProvider
663 */
664 public function pageRequestSendsNotFoundResponseWithInvalidCacheHashWithHavingFluidErrorHandling(string $uri)
665 {
666 $this->writeSiteConfiguration(
667 'website-local',
668 $this->buildSiteConfiguration(1000, 'https://website.local/'),
669 [],
670 $this->buildErrorHandlingConfiguration('Fluid', [404])
671 );
672
673 $response = $this->executeFrontendRequest(
674 new InternalRequest($uri),
675 $this->internalRequestContext
676 );
677
678 static::assertSame(
679 404,
680 $response->getStatusCode()
681 );
682 static::assertThat(
683 (string)$response->getBody(),
684 static::logicalOr(
685 static::stringContains('message: Request parameters could not be validated (&amp;cHash empty)'),
686 static::stringContains('message: Request parameters could not be validated (&amp;cHash comparison failed)')
687 )
688 );
689 }
690
691 /**
692 * @param string $uri
693 *
694 * @test
695 * @dataProvider pageRenderingStopsWithInvalidCacheHashDataProvider
696 * @todo Response body cannot be asserted since PageContentErrorHandler::handlePageError executes request via HTTP (not internally)
697 */
698 public function pageRequestSendsNotFoundResponseWithInvalidCacheHashWithHavingPageErrorHandling(string $uri)
699 {
700 $this->markTestSkipped('Skipped until PageContentErrorHandler::handlePageError does not use HTTP anymore');
701
702 $this->writeSiteConfiguration(
703 'website-local',
704 $this->buildSiteConfiguration(1000, 'https://website.local/'),
705 [],
706 $this->buildErrorHandlingConfiguration('Page', [404])
707 );
708
709 $response = $this->executeFrontendRequest(
710 new InternalRequest($uri),
711 $this->internalRequestContext
712 );
713
714 static::assertSame(
715 404,
716 $response->getStatusCode()
717 );
718 }
719
720 /**
721 * @param string $uri
722 *
723 * @test
724 * @dataProvider pageRenderingStopsWithInvalidCacheHashDataProvider
725 */
726 public function pageRequestSendsNotFoundResponseWithInvalidCacheHashWithHavingPhpErrorHandling(string $uri)
727 {
728 $this->writeSiteConfiguration(
729 'website-local',
730 $this->buildSiteConfiguration(1000, 'https://website.local/'),
731 [],
732 $this->buildErrorHandlingConfiguration('PHP', [404])
733 );
734
735 $response = $this->executeFrontendRequest(
736 new InternalRequest($uri),
737 $this->internalRequestContext
738 );
739 $json = json_decode((string)$response->getBody(), true);
740
741 static::assertSame(
742 404,
743 $response->getStatusCode()
744 );
745 static::assertThat(
746 $json['message'] ?? null,
747 static::logicalOr(
748 static::identicalTo('Request parameters could not be validated (&cHash empty)'),
749 static::identicalTo('Request parameters could not be validated (&cHash comparison failed)')
750 )
751 );
752 }
753
754 /**
755 * @return array
756 */
757 public function pageIsRenderedWithValidCacheHashDataProvider(): array
758 {
759 $domainPaths = [
760 // @todo Implicit strict mode handling when calling non-existent site
761 // '/',
762 // 'https://localhost/',
763 'https://website.local/',
764 ];
765
766 // cHash has been calculated with encryption key set to
767 // '4408d27a916d51e624b69af3554f516dbab61037a9f7b9fd6f81b4d3bedeccb6'
768 $queries = [
769 // @todo Currently fails since cHash is verified after(!) redirect to page 1100
770 // '?&cHash=7d1f13fa91159dac7feb3c824936b39d&id=1000',
771 '?&cHash=f42b850e435f0cedd366f5db749fc1af&id=1100',
772 ];
773
774 $customQueries = [
775 '&testing[value]=1',
776 ];
777
778 $dataSet = $this->wrapInArray(
779 $this->keysFromValues(
780 $this->meltStrings([$domainPaths, $queries, $customQueries])
781 )
782 );
783
784 return $dataSet;
785 }
786
787 /**
788 * @param string $uri
789 *
790 * @test
791 * @dataProvider pageIsRenderedWithValidCacheHashDataProvider
792 */
793 public function pageIsRenderedWithValidCacheHash($uri)
794 {
795 $this->writeSiteConfiguration(
796 'website-local',
797 $this->buildSiteConfiguration(1000, 'https://website.local/')
798 );
799
800 $response = $this->executeFrontendRequest(
801 new InternalRequest($uri),
802 $this->internalRequestContext
803 );
804 $responseStructure = ResponseContent::fromString(
805 (string)$response->getBody()
806 );
807 static::assertSame(
808 '1',
809 $responseStructure->getScopePath('getpost/testing.value')
810 );
811 }
812 }