[TASK] Prepare Frontend Tests for additional site handling tests
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / Unit / Middleware / SiteBaseRedirectResolverTest.php
1 <?php
2 declare(strict_types = 1);
3
4 namespace TYPO3\CMS\Frontend\Tests\Unit\Middleware;
5
6 /*
7 * This file is part of the TYPO3 CMS project.
8 *
9 * It is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License, either version 2
11 * of the License, or any later version.
12 *
13 * For the full copyright and license information, please read the
14 * LICENSE.txt file that was distributed with this source code.
15 *
16 * The TYPO3 project - inspiring people to share!
17 */
18
19 use Psr\Http\Message\ResponseInterface;
20 use Psr\Http\Message\ServerRequestInterface;
21 use Psr\Http\Server\RequestHandlerInterface;
22 use TYPO3\CMS\Core\Http\JsonResponse;
23 use TYPO3\CMS\Core\Http\NullResponse;
24 use TYPO3\CMS\Core\Http\ServerRequest;
25 use TYPO3\CMS\Core\Http\Uri;
26 use TYPO3\CMS\Core\Routing\SiteRouteResult;
27 use TYPO3\CMS\Core\Site\Entity\Site;
28 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
29 use TYPO3\CMS\Core\Tests\Functional\Fixtures\Frontend\PhpError;
30 use TYPO3\CMS\Frontend\Middleware\SiteBaseRedirectResolver;
31 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
32
33 class SiteBaseRedirectResolverTest extends UnitTestCase
34 {
35 /**
36 * @var bool Reset singletons created by subject
37 */
38 protected $resetSingletonInstances = true;
39
40 /**
41 * @var RequestHandlerInterface
42 */
43 protected $siteFoundRequestHandler;
44
45 /**
46 * Set up
47 */
48 protected function setUp(): void
49 {
50 // A request handler which expects a site to be found.
51 $this->siteFoundRequestHandler = new class implements RequestHandlerInterface {
52 public function handle(ServerRequestInterface $request): ResponseInterface
53 {
54 /** @var Site $site */
55 /** @var SiteLanguage $language */
56 $site = $request->getAttribute('site', false);
57 $language = $request->getAttribute('language', false);
58 if ($site && $language) {
59 return new JsonResponse(
60 [
61 'site' => $site->getIdentifier(),
62 'language-id' => $language->getLanguageId(),
63 'language-base' => (string)$language->getBase(),
64 'rootpage' => $site->getRootPageId()
65 ]
66 );
67 }
68 return new NullResponse();
69 }
70 };
71 }
72
73 /**
74 * @return array
75 */
76 public function doRedirectOnMissingOrSuperfluousRequestUrlDataProvider(): array
77 {
78 $site1 = new Site('outside-site', 13, [
79 'base' => 'https://twenty.one/',
80 'languages' => [
81 0 => [
82 'languageId' => 0,
83 'locale' => 'en_US.UTF-8',
84 'base' => '/en/'
85 ],
86 1 => [
87 'languageId' => 1,
88 'locale' => 'fr_CA.UTF-8',
89 'base' => '/fr'
90 ]
91 ]
92 ]);
93 $site2 = new Site('sub-site', 14, [
94 'base' => 'https://twenty.one/mysubsite/',
95 'languages' => [
96 2 => [
97 'languageId' => 2,
98 'locale' => 'it_IT.UTF-8',
99 'base' => '/'
100 ]
101 ]
102 ]);
103
104 return [
105 'redirect to first language' => [
106 'https://twenty.one/',
107 'https://twenty.one/en/',
108 $site1,
109 null,
110 ''
111 ],
112 'redirect to first language adding a slash' => [
113 'https://twenty.one/en',
114 'https://twenty.one/en/',
115 $site1,
116 $site1->getLanguageById(0),
117 ''
118 ],
119 'redirect to second language removing a slash' => [
120 'https://twenty.one/fr/',
121 'https://twenty.one/fr',
122 $site1,
123 $site1->getLanguageById(1),
124 '/'
125 ],
126 'redirect to subsite by adding a slash' => [
127 'https://twenty.one/mysubsite',
128 'https://twenty.one/mysubsite/',
129 $site2,
130 null,
131 ''
132 ],
133 ];
134 }
135
136 /**
137 * @param string $incomingUrl
138 * @param string $expectedRedirectUrl
139 * @param Site $site
140 * @param SiteLanguage|null $language
141 * @param string $tail
142 * @dataProvider doRedirectOnMissingOrSuperfluousRequestUrlDataProvider
143 * @test
144 */
145 public function doRedirectOnMissingOrSuperfluousRequestUrl(
146 string $incomingUrl,
147 string $expectedRedirectUrl,
148 Site $site,
149 ?SiteLanguage $language,
150 string $tail
151 ) {
152 $routeResult = new SiteRouteResult(new Uri($incomingUrl), $site, $language, $tail);
153 $request = new ServerRequest($incomingUrl, 'GET');
154 $request = $request->withAttribute('site', $site);
155 $request = $request->withAttribute('language', $language);
156 $request = $request->withAttribute('routing', $routeResult);
157
158 $subject = new SiteBaseRedirectResolver();
159 $response = $subject->process($request, $this->siteFoundRequestHandler);
160 $this->assertEquals(307, $response->getStatusCode());
161 $this->assertEquals($expectedRedirectUrl, $response->getHeader('Location')[0] ?? '');
162 }
163
164 /**
165 * @return array
166 */
167 public function checkIf404IsSiteLanguageIsDisabledInFrontendDataProvider(): array
168 {
169 return [
170 'disabled site language' => ['https://twenty.one/en/pilots/', 404, 0],
171 'enabled site language' => ['https://twenty.one/fr/pilots/', 200, 1],
172 ];
173 }
174
175 /**
176 * @param string $url
177 * @param int $expectedStatusCode
178 * @param int $languageId
179 *
180 * @test
181 * @dataProvider checkIf404IsSiteLanguageIsDisabledInFrontendDataProvider
182 */
183 public function checkIf404IsSiteLanguageIsDisabledInFrontend(
184 string $url,
185 int $expectedStatusCode,
186 int $languageId
187 ) {
188 $site = new Site('mixed-site', 13, [
189 'base' => '/',
190 'errorHandling' => [
191 [
192 'errorCode' => 404,
193 'errorHandler' => 'PHP',
194 'errorPhpClassFQCN' => PhpError::class
195 ]
196 ],
197 'languages' => [
198 0 => [
199 'languageId' => 0,
200 'locale' => 'en_US.UTF-8',
201 'base' => '/en/',
202 'enabled' => false
203 ],
204 1 => [
205 'languageId' => 1,
206 'locale' => 'fr_CA.UTF-8',
207 'base' => '/fr/',
208 'enabled' => true
209 ]
210 ]
211 ]);
212
213 // Request to default page
214 $request = new ServerRequest($url, 'GET');
215 $request = $request->withAttribute('site', $site);
216 $request = $request->withAttribute('language', $site->getLanguageById($languageId));
217 $subject = new SiteBaseRedirectResolver();
218 $response = $subject->process($request, $this->siteFoundRequestHandler);
219 $this->assertEquals($expectedStatusCode, $response->getStatusCode());
220 }
221 }