‪TYPO3CMS  ‪main
CanonicalGeneratorTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
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 
19 
20 use PHPUnit\Framework\Attributes\DataProvider;
21 use PHPUnit\Framework\Attributes\Test;
22 use Symfony\Component\DependencyInjection\Container;
33 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\TypoScriptInstruction;
34 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
35 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
36 
37 final class ‪CanonicalGeneratorTest extends FunctionalTestCase
38 {
40 
41  protected const ‪LANGUAGE_PRESETS = [
42  'EN' => ['id' => 0, 'title' => 'English', 'locale' => 'en_US.UTF8'],
43  ];
44 
45  protected array ‪$coreExtensionsToLoad = ['seo'];
46 
47  protected function ‪setUp(): void
48  {
49  parent::setUp();
51  'website-local',
52  $this->‪buildSiteConfiguration(1, 'http://localhost/'),
53  [
54  $this->‪buildDefaultLanguageConfiguration('EN', '/'),
55  ]
56  );
58  'website-example',
59  $this->‪buildSiteConfiguration(100, 'http://example.com/'),
60  [
61  $this->‪buildDefaultLanguageConfiguration('EN', '/'),
62  ]
63  );
65  'dummy',
66  $this->‪buildSiteConfiguration(200, '/'),
67  [
68  $this->‪buildDefaultLanguageConfiguration('EN', '/'),
69  ]
70  );
71  $this->importCSVDataSet(__DIR__ . '/../Fixtures/pages-canonical.csv');
72  $this->setUpFrontendRootPage(
73  1,
74  ['EXT:seo/Tests/Functional/Fixtures/Canonical.typoscript']
75  );
76  }
77 
78  public static function ‪generateDataProvider(): array
79  {
80  return [
81  'uid: 1 with canonical_link' => [
82  'http://localhost/',
83  '<link rel="canonical" href="http://localhost/"/>' . chr(10),
84  ],
85  'uid: 2 with canonical_link' => [
86  'http://localhost/dummy-1-2',
87  '<link rel="canonical" href="http://localhost/dummy-1-2"/>' . chr(10),
88  ],
89  'uid: 3 with canonical_link AND content_from_pid = 2' => [
90  'http://localhost/dummy-1-3',
91  '<link rel="canonical" href="http://localhost/dummy-1-3"/>' . chr(10),
92  ],
93  'uid: 4 without canonical_link AND content_from_pid = 2' => [
94  'http://localhost/dummy-1-4',
95  '<link rel="canonical" href="http://localhost/dummy-1-2"/>' . chr(10),
96  ],
97  'uid: 5 without canonical_link AND without content_from_pid set' => [
98  'http://localhost/dummy-1-2-5',
99  '<link rel="canonical" href="http://localhost/dummy-1-2-5"/>' . chr(10),
100  ],
101  'uid: 8 without canonical_link AND content_from_pid = 9 (but target page is hidden) results in no canonical' => [
102  'http://localhost/dummy-1-2-8',
103  '',
104  ],
105  'uid: 10 no index' => [
106  'http://localhost/dummy-1-2-10',
107  '',
108  ],
109  'uid: 11 with mount_pid_ol = 0' => [
110  'http://localhost/dummy-1-2-11',
111  '<link rel="canonical" href="http://localhost/dummy-1-2-11"/>' . chr(10),
112  ],
113  'uid: 12 with mount_pid_ol = 1' => [
114  'http://localhost/dummy-1-2-12',
115  '<link rel="canonical" href="http://example.com/"/>' . chr(10),
116  ],
117  'subpage of page with mount_pid_ol = 0' => [
118  'http://localhost/dummy-1-2-11/subpage-of-new-root',
119  '<link rel="canonical" href="http://example.com/subpage-of-new-root"/>' . chr(10),
120  ],
121  'subpage of page with mount_pid_ol = 1' => [
122  'http://localhost/dummy-1-2-12/subpage-of-new-root',
123  '<link rel="canonical" href="http://example.com/subpage-of-new-root"/>' . chr(10),
124  ],
125  'mountpoint to page without siteroot' => [
126  'http://localhost/dummy-1-2-13',
127  '',
128  ],
129  'subpage of mountpoint without siteroot' => [
130  'http://localhost/dummy-1-2-13/imprint',
131  '',
132  ],
133  'uid: 14 typoscript setting config.disableCanonical' => [
134  'http://localhost/no-canonical',
135  '',
136  ],
137  ];
138  }
139 
140  #[DataProvider('generateDataProvider')]
141  #[Test]
142  public function ‪generate(string $targetUri, string $expectedCanonicalUrl): void
143  {
144  $response = $this->executeFrontendSubRequest(
145  (new InternalRequest($targetUri))->withInstructions([$this->‪buildPageTypoScript()])
146  );
147  if ($expectedCanonicalUrl) {
148  self::assertStringContainsString($expectedCanonicalUrl, (string)$response->getBody());
149  } else {
150  self::assertStringNotContainsString('<link rel="canonical"', (string)$response->getBody());
151  }
152  }
153 
154  #[Test]
156  {
157  $modifyUrlForCanonicalTagEvent = null;
158 
160  $container = $this->get('service_container');
161  $container->set(
162  'modify-url-for-canonical-tag-listener',
163  static function (‪ModifyUrlForCanonicalTagEvent $event) use (&$modifyUrlForCanonicalTagEvent) {
164  $modifyUrlForCanonicalTagEvent = $event;
165  $modifyUrlForCanonicalTagEvent->‪setUrl('https://canonical-url.com');
166  }
167  );
168 
169  $eventListener = $container->get(ListenerProvider::class);
170  $eventListener->addListener(ModifyUrlForCanonicalTagEvent::class, 'modify-url-for-canonical-tag-listener');
171 
172  $request = new ‪ServerRequest('https://example.com');
173  $request = $request->withAttribute('frontend.controller', $this->createMock(TypoScriptFrontendController::class));
174  $pageInformation = new ‪PageInformation();
175  $pageInformation->setId(123);
176  $pageRecord = [
177  'uid' => 123,
178  'no_index' => 1,
179  'canonical_link' => '',
180  ];
181  $pageInformation->setPageRecord($pageRecord);
182  $request = $request->withAttribute('frontend.page.information', $pageInformation);
183  $typoScript = new ‪FrontendTypoScript(new ‪RootNode(), [], [], []);
184  $typoScript->setConfigArray([]);
185  $request = $request->withAttribute('frontend.typoscript', $typoScript);
186  $this->get(CanonicalGenerator::class)->‪generate(['request' => $request]);
187 
188  self::assertInstanceOf(ModifyUrlForCanonicalTagEvent::class, $modifyUrlForCanonicalTagEvent);
189  self::assertSame('https://canonical-url.com', $modifyUrlForCanonicalTagEvent->getUrl());
190  self::assertSame('https://example.com', (string)$modifyUrlForCanonicalTagEvent->getRequest()->getUri());
191  self::assertSame(123, $modifyUrlForCanonicalTagEvent->getPage()->getPageId());
192  self::assertInstanceOf(CanonicalGenerationDisabledException::class, $modifyUrlForCanonicalTagEvent->getCanonicalGenerationDisabledException());
193  self::assertSame(1706104147, $modifyUrlForCanonicalTagEvent->getCanonicalGenerationDisabledException()->getCode());
194  }
195 
196  private function ‪buildPageTypoScript(): TypoScriptInstruction
197  {
198  return (new TypoScriptInstruction())
199  ->withTypoScript([
200  'page' => 'PAGE',
201  'page.' => [
202  'typeNum' => 0,
203  ],
204  ]);
205  }
206 }
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait
Definition: SiteBasedTestTrait.php:37
‪TYPO3\CMS\Seo\Tests\Functional\Canonical
Definition: CanonicalGeneratorTest.php:18
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\writeSiteConfiguration
‪writeSiteConfiguration(string $identifier, array $site=[], array $languages=[], array $errorHandling=[])
Definition: SiteBasedTestTrait.php:50
‪TYPO3\CMS\Seo\Tests\Functional\Canonical\CanonicalGeneratorTest\buildPageTypoScript
‪buildPageTypoScript()
Definition: CanonicalGeneratorTest.php:195
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildSiteConfiguration
‪buildSiteConfiguration(int $rootPageId, string $base='')
Definition: SiteBasedTestTrait.php:88
‪TYPO3\CMS\Seo\Tests\Functional\Canonical\CanonicalGeneratorTest\generateDataProvider
‪static generateDataProvider()
Definition: CanonicalGeneratorTest.php:77
‪TYPO3\CMS\Seo\Tests\Functional\Canonical\CanonicalGeneratorTest\$coreExtensionsToLoad
‪array $coreExtensionsToLoad
Definition: CanonicalGeneratorTest.php:44
‪TYPO3\CMS\Seo\Tests\Functional\Canonical\CanonicalGeneratorTest\generate
‪generate(string $targetUri, string $expectedCanonicalUrl)
Definition: CanonicalGeneratorTest.php:141
‪TYPO3\CMS\Seo\Tests\Functional\Canonical\CanonicalGeneratorTest
Definition: CanonicalGeneratorTest.php:38
‪TYPO3\CMS\Core\Http\ServerRequest
Definition: ServerRequest.php:39
‪TYPO3\CMS\Seo\Tests\Functional\Canonical\CanonicalGeneratorTest\LANGUAGE_PRESETS
‪const LANGUAGE_PRESETS
Definition: CanonicalGeneratorTest.php:40
‪TYPO3\CMS\Seo\Canonical\CanonicalGenerator
Definition: CanonicalGenerator.php:37
‪TYPO3\CMS\Seo\Tests\Functional\Canonical\CanonicalGeneratorTest\setUp
‪setUp()
Definition: CanonicalGeneratorTest.php:46
‪TYPO3\CMS\Seo\Exception\CanonicalGenerationDisabledException
Definition: CanonicalGenerationDisabledException.php:25
‪TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent
Definition: ModifyUrlForCanonicalTagEvent.php:28
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:58
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildDefaultLanguageConfiguration
‪buildDefaultLanguageConfiguration(string $identifier, string $base)
Definition: SiteBasedTestTrait.php:98
‪TYPO3\CMS\Core\TypoScript\AST\Node\RootNode
Definition: RootNode.php:26
‪TYPO3\CMS\Seo\Tests\Functional\Canonical\CanonicalGeneratorTest\afterContentObjectRendererInitializedEventIsCalled
‪afterContentObjectRendererInitializedEventIsCalled()
Definition: CanonicalGeneratorTest.php:154
‪TYPO3\CMS\Seo\Event\ModifyUrlForCanonicalTagEvent\setUrl
‪setUrl(string $url)
Definition: ModifyUrlForCanonicalTagEvent.php:41
‪TYPO3\CMS\Core\TypoScript\FrontendTypoScript
Definition: FrontendTypoScript.php:30
‪TYPO3\CMS\Core\EventDispatcher\ListenerProvider
Definition: ListenerProvider.php:30
‪TYPO3\CMS\Frontend\Page\PageInformation
Definition: PageInformation.php:28