[TASK] Restructure nightly plans in stages a 50 jobs
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / Functional / SiteHandling / EnhancerSiteRequestTest.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\Utility\ArrayUtility;
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
25 /**
26 * Test case for frontend requests having site handling configured using enhancers.
27 */
28 class EnhancerSiteRequestTest extends AbstractTestCase
29 {
30 /**
31 * @var string
32 */
33 private $siteTitle = 'A Company that Manufactures Everything Inc';
34
35 /**
36 * @var InternalRequestContext
37 */
38 private $internalRequestContext;
39
40 public static function setUpBeforeClass(): void
41 {
42 parent::setUpBeforeClass();
43 static::initializeDatabaseSnapshot();
44 }
45
46 public static function tearDownAfterClass(): void
47 {
48 static::destroyDatabaseSnapshot();
49 parent::tearDownAfterClass();
50 }
51
52 protected function setUp(): void
53 {
54 parent::setUp();
55
56 // these settings are forwarded to the frontend sub-request as well
57 $this->internalRequestContext = (new InternalRequestContext())
58 ->withGlobalSettings(['TYPO3_CONF_VARS' => static::TYPO3_CONF_VARS]);
59
60 $this->writeSiteConfiguration(
61 'acme-com',
62 $this->buildSiteConfiguration(1000, 'https://acme.com/'),
63 [
64 $this->buildDefaultLanguageConfiguration('EN', 'https://acme.us/'),
65 $this->buildLanguageConfiguration('FR', 'https://acme.fr/', ['EN']),
66 $this->buildLanguageConfiguration('FR-CA', 'https://acme.ca/', ['FR', 'EN']),
67 ]
68 );
69
70 $this->withDatabaseSnapshot(function () {
71 $this->setUpDatabase();
72 });
73 }
74
75 protected function setUpDatabase()
76 {
77 $backendUser = $this->setUpBackendUserFromFixture(1);
78 Bootstrap::initializeLanguageObject();
79
80 $scenarioFile = __DIR__ . '/Fixtures/SlugScenario.yaml';
81 $factory = DataHandlerFactory::fromYamlFile($scenarioFile);
82 $writer = DataHandlerWriter::withBackendUser($backendUser);
83 $writer->invokeFactory($factory);
84 static::failIfArrayIsNotEmpty(
85 $writer->getErrors()
86 );
87
88 $this->setUpFrontendRootPage(
89 1000,
90 [
91 'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/LinkRequest.typoscript',
92 ],
93 [
94 'title' => 'ACME Root',
95 'sitetitle' => $this->siteTitle,
96 ]
97 );
98 }
99
100 protected function tearDown(): void
101 {
102 unset($this->internalRequestContext);
103 parent::tearDown();
104 }
105
106 /**
107 * @param array $aspect
108 * @param array $enhancerLanguageUris
109 * @param array $enhancers
110 * @param string $variableName
111 * @param array $templateOptions
112 * @return array
113 */
114 protected function createDataSet(
115 array $aspect,
116 array $enhancerLanguageUris,
117 array $enhancers,
118 string $variableName = 'value',
119 array $templateOptions = []
120 ): array {
121 $dataSet = [];
122 foreach ($enhancers as $enhancer) {
123 $enhancerType = $enhancer['enhancer']['type'];
124 foreach ($enhancerLanguageUris[$enhancerType] as $languageId => $uri) {
125 $expectation = $enhancer['arguments'];
126 $expectation['staticArguments'] = $expectation['staticArguments'] ?? [];
127 $expectation['dynamicArguments'] = $expectation['dynamicArguments'] ?? [];
128 $expectation['queryArguments'] = $expectation['queryArguments'] ?? [];
129 if (preg_match('#\?cHash=([a-z0-9]+)#i', $uri, $matches)) {
130 $expectation['dynamicArguments']['cHash'] = $matches[1];
131 $expectation['queryArguments']['cHash'] = $matches[1];
132 }
133 $dataSet[] = [
134 array_merge(
135 $enhancer['enhancer'],
136 ['aspects' => [$variableName => $aspect]]
137 ),
138 $uri,
139 $languageId,
140 $expectation,
141 ];
142 }
143 }
144 $templatePrefix = isset($templateOptions['prefix']) ? $templateOptions['prefix'] : '';
145 $templateSuffix = isset($templateOptions['suffix']) ? $templateOptions['suffix'] : '';
146 return $this->keysFromTemplate(
147 $dataSet,
148 $templatePrefix . 'enhancer:%1$s, lang:%3$d' . $templateSuffix,
149 function (array $items) {
150 array_splice(
151 $items,
152 0,
153 1,
154 $items[0]['type']
155 );
156 return $items;
157 }
158 );
159 }
160
161 /**
162 * @param array $options
163 * @param bool $isStatic
164 * @return array
165 */
166 protected function getEnhancers(array $options = [], bool $isStatic = false): array
167 {
168 $inArguments = $isStatic ? 'staticArguments' : 'dynamicArguments';
169 $options = array_merge(['name' => 'enhance', 'value' => 100], $options);
170 return [
171 [
172 'arguments' => [
173 $inArguments => [
174 'value' => (string)$options['value'],
175 ],
176 ],
177 'enhancer' => [
178 'type' => 'Simple',
179 'routePath' => sprintf('/%s/{value}', $options['name']),
180 '_arguments' => [],
181 ],
182 ],
183 [
184 'arguments' => [
185 $inArguments => [
186 'testing' => [
187 'value' => (string)$options['value'],
188 ],
189 ],
190 ],
191 'enhancer' => [
192 'type' => 'Plugin',
193 'routePath' => sprintf('/%s/{value}', $options['name']),
194 'namespace' => 'testing',
195 '_arguments' => [],
196 ],
197 ],
198 [
199 'arguments' => array_merge_recursive([
200 $inArguments => [
201 'tx_testing_link' => [
202 'value' => (string)$options['value'],
203 ],
204 ],
205 ], [
206 'staticArguments' => [
207 'tx_testing_link' => [
208 'controller' => 'Link',
209 'action' => 'index',
210 ],
211 ],
212 ]),
213 'enhancer' => [
214 'type' => 'Extbase',
215 'routes' => [
216 [
217 'routePath' => sprintf('/%s/{value}', $options['name']),
218 '_controller' => 'Link::index',
219 '_arguments' => [],
220 ],
221 ],
222 'extension' => 'testing',
223 'plugin' => 'link',
224 ],
225 ],
226 ];
227 }
228
229 /**
230 * @return array
231 */
232 protected function createPageTypeDecorator(): array
233 {
234 return [
235 'type' => 'PageType',
236 'default' => '.html',
237 'index' => 'index',
238 'map' => [
239 '.html' => 0,
240 'menu.json' => 10,
241 ]
242 ];
243 }
244
245 /**
246 * @param string|array|null $options
247 * @return array
248 */
249 public function localeModifierDataProvider($options = null): array
250 {
251 if (!is_array($options)) {
252 $options = [];
253 }
254 $aspect = [
255 'type' => 'LocaleModifier',
256 'default' => 'enhance',
257 'localeMap' => [
258 [
259 'locale' => 'fr_FR',
260 'value' => 'augmenter'
261 ]
262 ],
263 ];
264
265 $enhancerLanguageUris = [
266 'Simple' => [
267 '0' => 'https://acme.us/welcome/enhance/100%s?cHash=46227b4ce096dc78a4e71463326c9020',
268 '1' => 'https://acme.fr/bienvenue/augmenter/100%s?cHash=46227b4ce096dc78a4e71463326c9020',
269 ],
270 'Plugin' => [
271 '0' => 'https://acme.us/welcome/enhance/100%s?cHash=e24d3d2d5503baba670d827c3b9470c8',
272 '1' => 'https://acme.fr/bienvenue/augmenter/100%s?cHash=e24d3d2d5503baba670d827c3b9470c8',
273 ],
274 'Extbase' => [
275 '0' => 'https://acme.us/welcome/enhance/100%s?cHash=eef21771ab3c3dac3514b4479eedd5ff',
276 '1' => 'https://acme.fr/bienvenue/augmenter/100%s?cHash=eef21771ab3c3dac3514b4479eedd5ff',
277 ]
278 ];
279
280 $pathSuffix = $options['pathSuffix'] ?? '';
281 foreach ($enhancerLanguageUris as &$enhancerUris) {
282 $enhancerUris = array_map(
283 function (string $enhancerUri) use ($pathSuffix) {
284 return sprintf($enhancerUri, $pathSuffix);
285 },
286 $enhancerUris
287 );
288 }
289
290 return $this->createDataSet(
291 $aspect,
292 $enhancerLanguageUris,
293 $this->getEnhancers(['name' => '{enhance_name}']),
294 'enhance_name',
295 ['prefix' => 'localeModifier/']
296 );
297 }
298
299 /**
300 * @param array $enhancer
301 * @param string $targetUri
302 * @param int $expectedLanguageId
303 * @param array $expectation
304 *
305 * @test
306 * @dataProvider localeModifierDataProvider
307 */
308 public function localeModifierIsApplied(array $enhancer, string $targetUri, int $expectedLanguageId, array $expectation)
309 {
310 $this->assertPageArgumentsEquals(
311 $enhancer,
312 $targetUri,
313 $expectedLanguageId,
314 $expectation
315 );
316 }
317
318 /**
319 * @param string|array|null $options
320 * @return array
321 */
322 public function persistedAliasMapperDataProvider($options = null): array
323 {
324 if (!is_array($options)) {
325 $options = [];
326 }
327 $aspect = [
328 'type' => 'PersistedAliasMapper',
329 'tableName' => 'pages',
330 'routeFieldName' => 'slug',
331 'routeValuePrefix' => '/',
332 ];
333
334 $enhancerLanguageUris = $this->populateToKeys(
335 ['Simple', 'Plugin', 'Extbase'],
336 [
337 '0' => sprintf('https://acme.us/welcome/enhance/welcome%s', $options['pathSuffix'] ?? ''),
338 '1' => sprintf('https://acme.fr/bienvenue/enhance/bienvenue%s', $options['pathSuffix'] ?? ''),
339 ]
340 );
341
342 return $this->createDataSet(
343 $aspect,
344 $enhancerLanguageUris,
345 $this->getEnhancers(['value' => 1100], true),
346 'value',
347 ['prefix' => 'persistedAliasMapper/']
348 );
349 }
350
351 /**
352 * @param array $enhancer
353 * @param string $targetUri
354 * @param int $expectedLanguageId
355 * @param array $expectation
356 *
357 * @test
358 * @dataProvider persistedAliasMapperDataProvider
359 */
360 public function persistedAliasMapperIsApplied(array $enhancer, string $targetUri, int $expectedLanguageId, array $expectation)
361 {
362 $this->assertPageArgumentsEquals(
363 $enhancer,
364 $targetUri,
365 $expectedLanguageId,
366 $expectation
367 );
368 }
369
370 /**
371 * @param string|array|null $options
372 * @return array
373 */
374 public function persistedPatternMapperDataProvider($options = null): array
375 {
376 if (!is_array($options)) {
377 $options = [];
378 }
379 $aspect = [
380 'type' => 'PersistedPatternMapper',
381 'tableName' => 'pages',
382 'routeFieldPattern' => '^(?P<subtitle>.+)-(?P<uid>\d+)$',
383 'routeFieldResult' => '{subtitle}-{uid}',
384 ];
385
386 $enhancerLanguageUris = $this->populateToKeys(
387 ['Simple', 'Plugin', 'Extbase'],
388 [
389 '0' => sprintf('https://acme.us/welcome/enhance/hello-and-welcome-1100%s', $options['pathSuffix'] ?? ''),
390 '1' => sprintf('https://acme.fr/bienvenue/enhance/salut-et-bienvenue-1100%s', $options['pathSuffix'] ?? ''),
391 ]
392 );
393
394 return $this->createDataSet(
395 $aspect,
396 $enhancerLanguageUris,
397 $this->getEnhancers(['value' => 1100], true),
398 'value',
399 ['prefix' => 'persistedPatternMapper/']
400 );
401 }
402
403 /**
404 * @param array $enhancer
405 * @param string $targetUri
406 * @param int $expectedLanguageId
407 * @param array $expectation
408 *
409 * @test
410 * @dataProvider persistedPatternMapperDataProvider
411 */
412 public function persistedPatternMapperIsApplied(array $enhancer, string $targetUri, int $expectedLanguageId, array $expectation)
413 {
414 $this->assertPageArgumentsEquals(
415 $enhancer,
416 $targetUri,
417 $expectedLanguageId,
418 $expectation
419 );
420 }
421
422 /**
423 * @param string|array|null $options
424 * @return array
425 */
426 public function staticValueMapperDataProvider($options = null): array
427 {
428 if (!is_array($options)) {
429 $options = [];
430 }
431 $aspect = [
432 'type' => 'StaticValueMapper',
433 'map' => [
434 'hundred' => 100,
435 ],
436 'localeMap' => [
437 [
438 'locale' => 'fr_FR',
439 'map' => [
440 'cent' => 100,
441 ],
442 ]
443 ],
444 ];
445
446 $enhancerLanguageUris = $this->populateToKeys(
447 ['Simple', 'Plugin', 'Extbase'],
448 [
449 '0' => sprintf('https://acme.us/welcome/enhance/hundred%s', $options['pathSuffix'] ?? ''),
450 '1' => sprintf('https://acme.fr/bienvenue/enhance/cent%s', $options['pathSuffix'] ?? ''),
451 ]
452 );
453
454 return $this->createDataSet(
455 $aspect,
456 $enhancerLanguageUris,
457 $this->getEnhancers([], true),
458 'value',
459 ['prefix' => 'staticValueMapper/']
460 );
461 }
462
463 /**
464 * @param array $enhancer
465 * @param string $targetUri
466 * @param int $expectedLanguageId
467 * @param array $expectation
468 *
469 * @test
470 * @dataProvider staticValueMapperDataProvider
471 */
472 public function staticValueMapperIsApplied(array $enhancer, string $targetUri, int $expectedLanguageId, array $expectation)
473 {
474 $this->assertPageArgumentsEquals(
475 $enhancer,
476 $targetUri,
477 $expectedLanguageId,
478 $expectation
479 );
480 }
481
482 /**
483 * @param string|array|null $options
484 * @return array
485 */
486 public function staticRangeMapperDataProvider($options = null): array
487 {
488 if (!is_array($options)) {
489 $options = [];
490 }
491 $aspect = [
492 'type' => 'StaticRangeMapper',
493 'start' => '1',
494 'end' => '100',
495 ];
496
497 $dataSet = [];
498 foreach (range(10, 100, 30) as $value) {
499 $enhancerLanguageUris = $this->populateToKeys(
500 ['Simple', 'Plugin', 'Extbase'],
501 [
502 '0' => sprintf('https://acme.us/welcome/enhance/%s%s', $value, $options['pathSuffix'] ?? ''),
503 '1' => sprintf('https://acme.fr/bienvenue/enhance/%s%s', $value, $options['pathSuffix'] ?? ''),
504 ]
505 );
506
507 $dataSet = array_merge(
508 $dataSet,
509 $this->createDataSet(
510 $aspect,
511 $enhancerLanguageUris,
512 $this->getEnhancers(['value' => $value], true),
513 'value',
514 ['prefix' => 'staticRangeMapper/', 'suffix' => sprintf(', value:%d', $value)]
515 )
516 );
517 }
518 return $dataSet;
519 }
520
521 /**
522 * @param array $enhancer
523 * @param string $targetUri
524 * @param int $expectedLanguageId
525 * @param array $expectation
526 *
527 * @test
528 * @dataProvider staticRangeMapperDataProvider
529 */
530 public function staticRangeMapperIsApplied(array $enhancer, string $targetUri, int $expectedLanguageId, array $expectation)
531 {
532 $this->assertPageArgumentsEquals(
533 $enhancer,
534 $targetUri,
535 $expectedLanguageId,
536 $expectation
537 );
538 }
539
540 /**
541 * @return array
542 */
543 public function pageTypeDecoratorIsAppliedDataProvider(): array
544 {
545 $instructions = [
546 ['pathSuffix' => '.html', 'type' => null],
547 ['pathSuffix' => '.html', 'type' => 0],
548 ['pathSuffix' => '/menu.json', 'type' => 10],
549 ];
550
551 $dataSet = [];
552 foreach ($instructions as $instruction) {
553 $templateSuffix = sprintf(
554 ' [%s=>%s]',
555 $instruction['pathSuffix'],
556 $instruction['type'] ?? 'null'
557 );
558 $expectedPageType = (string)($instruction['type'] ?? 0);
559 $dataProviderOptions = [
560 'pathSuffix' => $instruction['pathSuffix'],
561 ];
562 $dataSetCandidates = array_merge(
563 $this->localeModifierDataProvider($dataProviderOptions),
564 $this->persistedAliasMapperDataProvider($dataProviderOptions),
565 $this->persistedPatternMapperDataProvider($dataProviderOptions),
566 $this->staticValueMapperDataProvider($dataProviderOptions),
567 $this->staticRangeMapperDataProvider($dataProviderOptions)
568 );
569 // add expected pageType to data set candidates
570 $dataSetCandidates = array_map(
571 function (array $dataSetCandidate) use ($expectedPageType) {
572 $dataSetCandidate[3]['pageType'] = $expectedPageType;
573 return $dataSetCandidate;
574 },
575 $dataSetCandidates
576 );
577 $dataSetCandidatesKeys = array_map(
578 function (string $dataSetCandidatesKey) use ($templateSuffix) {
579 return $dataSetCandidatesKey . $templateSuffix;
580 },
581 array_keys($dataSetCandidates)
582 );
583 $dataSet = array_merge(
584 $dataSet,
585 array_combine($dataSetCandidatesKeys, $dataSetCandidates)
586 );
587 }
588 return $dataSet;
589 }
590
591 /**
592 * @param array $enhancer
593 * @param string $targetUri
594 * @param int $expectedLanguageId
595 * @param array $expectation
596 *
597 * @test
598 * @dataProvider pageTypeDecoratorIsAppliedDataProvider
599 */
600 public function pageTypeDecoratorIsApplied(array $enhancer, string $targetUri, int $expectedLanguageId, array $expectation)
601 {
602 $this->mergeSiteConfiguration('acme-com', [
603 'routeEnhancers' => [
604 'Enhancer' => $enhancer,
605 'PageType' => $this->createPageTypeDecorator()
606 ]
607 ]);
608
609 $allParameters = array_replace_recursive(
610 $expectation['dynamicArguments'],
611 $expectation['staticArguments']
612 );
613 $expectation['pageId'] = 1100;
614 $expectation['languageId'] = $expectedLanguageId;
615 $expectation['requestQueryParams'] = $allParameters;
616 $expectation['_GET'] = $allParameters;
617
618 $response = $this->executeFrontendRequest(
619 new InternalRequest($targetUri),
620 $this->internalRequestContext,
621 true
622 );
623
624 $pageArguments = json_decode((string)$response->getBody(), true);
625 self::assertEquals($expectation, $pageArguments);
626 }
627
628 public function routeIdentifiersAreResolvedDataProvider(): array
629 {
630 return [
631 // namespace[value]
632 'namespace[value] ? test' => [
633 'namespace',
634 'value',
635 'test',
636 ],
637 'namespace[value] ? x^31' => [
638 'namespace',
639 'value',
640 str_repeat('x', 31),
641 ],
642 'namespace[value] ? x^32' => [
643 'namespace',
644 'value',
645 str_repeat('x', 32),
646 ],
647 'namespace[value] ? x^33' => [
648 'namespace',
649 'value',
650 str_repeat('x', 33),
651 ],
652 'namespace[value] ? 1^32 (type-cast)' => [
653 'namespace',
654 'value',
655 str_repeat('1', 32),
656 ],
657 // md5('namespace__@otne3') is 60360798585102000952995164024754 (numeric)
658 // md5('ximaz') is 61529519452809720693702583126814 (numeric)
659 'namespace[@otne3] ? numeric-md5 (type-cast)' => [
660 'namespace',
661 '@otne3',
662 md5('ximaz'),
663 ],
664 'namespace[value] ? namespace__value' => [
665 'namespace',
666 'value',
667 'namespace__value',
668 ],
669 'namespace[value] ? namespace/value' => [
670 'namespace',
671 'value',
672 'namespace/value',
673 'The requested URL is not distinct',
674 ],
675 'namespace[value] ? namespace__other' => [
676 'namespace',
677 'value',
678 'namespace__other',
679 ],
680 'namespace[value] ? namespace/other' => [
681 'namespace',
682 'value',
683 'namespace/other',
684 ],
685 // namespace[any/value]
686 'namespace[any/value] ? x^31' => [
687 'namespace',
688 'any/value',
689 str_repeat('x', 31),
690 ],
691 'namespace[any/value] ? x^32' => [
692 'namespace',
693 'any/value',
694 str_repeat('x', 32),
695 ],
696 'namespace[any/value] ? namespace__any__value' => [
697 'namespace',
698 'any/value',
699 'namespace__any__value',
700 ],
701 'namespace[any/value] ? namespace/any/value' => [
702 'namespace',
703 'any/value',
704 'namespace/any/value',
705 'The requested URL is not distinct',
706 ],
707 'namespace[any/value] ? namespace__any__other' => [
708 'namespace',
709 'any/value',
710 'namespace__any__other',
711 ],
712 'namespace[any/value] ? namespace/any/other' => [
713 'namespace',
714 'any/value',
715 'namespace/any/other',
716 ],
717 // namespace[@any/value]
718 'namespace[@any/value] ? x^31' => [
719 'namespace',
720 '@any/value',
721 str_repeat('x', 31),
722 ],
723 'namespace[@any/value] ? x^32' => [
724 'namespace',
725 '@any/value',
726 str_repeat('x', 32),
727 ],
728 'namespace[@any/value] ? md5(namespace__@any__value)' => [
729 'namespace',
730 '@any/value',
731 md5('namespace__@any__value'),
732 ],
733 'namespace[@any/value] ? namespace/@any/value' => [
734 'namespace',
735 '@any/value',
736 'namespace/@any/value',
737 'The requested URL is not distinct',
738 ],
739 'namespace[@any/value] ? md5(namespace__@any__other)' => [
740 'namespace',
741 '@any/value',
742 md5('namespace__@any__other'),
743 ],
744 'namespace[@any/value] ? namespace/@any/other' => [
745 'namespace',
746 '@any/value',
747 'namespace/@any/other',
748 ],
749 ];
750 }
751
752 /**
753 * @param string $namespace
754 * @param string $argumentName
755 * @param string $queryPath
756 * @param string|null $failureReason
757 *
758 * @test
759 * @dataProvider routeIdentifiersAreResolvedDataProvider
760 */
761 public function routeIdentifiersAreResolved(string $namespace, string $argumentName, string $queryPath, string $failureReason = null)
762 {
763 $query = [];
764 $routeValue = 'route-value';
765 $queryValue = 'parameter-value';
766 $query = ArrayUtility::setValueByPath($query, $queryPath, $queryValue);
767 $queryParameters = http_build_query($query, '', '&', PHP_QUERY_RFC3986);
768 $targetUri = sprintf('https://acme.us/welcome/%s?%s', $routeValue, $queryParameters);
769
770 $this->mergeSiteConfiguration('acme-com', [
771 'routeEnhancers' => ['Enhancer' => [
772 'type' => 'Plugin',
773 'routePath' => '/{name}',
774 '_arguments' => [
775 'name' => $argumentName,
776 ],
777 'namespace' => $namespace,
778 ]]
779 ]);
780
781 $response = $this->executeFrontendRequest(
782 new InternalRequest($targetUri),
783 $this->internalRequestContext,
784 true
785 );
786
787 $body = (string)$response->getBody();
788 if ($failureReason === null) {
789 $pageArguments = json_decode($body, true);
790 self::assertNotNull($pageArguments, 'PageArguments could not be resolved');
791
792 $expected = [];
793 $expected = ArrayUtility::setValueByPath($expected, $namespace . '/' . $argumentName, $routeValue);
794 $expected = ArrayUtility::setValueByPath($expected, $queryPath, $queryValue);
795 self::assertEquals($expected, $pageArguments['requestQueryParams']);
796 } else {
797 self::assertStringContainsString($failureReason, $body);
798 }
799 }
800
801 /**
802 * @param array $enhancer
803 * @param string $targetUri
804 * @param int $expectedLanguageId
805 * @param array $expectation
806 */
807 protected function assertPageArgumentsEquals(array $enhancer, string $targetUri, int $expectedLanguageId, array $expectation)
808 {
809 $this->mergeSiteConfiguration('acme-com', [
810 'routeEnhancers' => ['Enhancer' => $enhancer]
811 ]);
812
813 $allParameters = array_replace_recursive(
814 $expectation['dynamicArguments'],
815 $expectation['staticArguments']
816 );
817 $expectation['pageId'] = 1100;
818 $expectation['pageType'] = '0';
819 $expectation['languageId'] = $expectedLanguageId;
820 $expectation['requestQueryParams'] = $allParameters;
821 $expectation['_GET'] = $allParameters;
822
823 $response = $this->executeFrontendRequest(
824 new InternalRequest($targetUri),
825 $this->internalRequestContext,
826 true
827 );
828
829 $pageArguments = json_decode((string)$response->getBody(), true);
830 self::assertEquals($expectation, $pageArguments);
831 }
832 }