‪TYPO3CMS  ‪main
HrefLangGeneratorTest.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;
24 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory;
25 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter;
26 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
27 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
28 
29 final class ‪HrefLangGeneratorTest extends FunctionalTestCase
30 {
32 
33  protected array ‪$coreExtensionsToLoad = ['seo'];
34 
38  protected const ‪LANGUAGE_PRESETS = [
39  'EN' => ['id' => 0, 'title' => 'English', 'locale' => 'en_US.UTF8'],
40  'DE' => ['id' => 1, 'title' => 'German', 'locale' => 'de_DE.UTF8'],
41  'DE-CH' => ['id' => 2, 'title' => 'Swiss German', 'locale' => 'de_CH.UTF8'],
42  'NL' => ['id' => 3, 'title' => 'Dutch', 'locale' => 'nl_NL.UTF8'],
43  'FR' => ['id' => 4, 'title' => 'French', 'locale' => 'fr_FR.UTF8'],
44  'DA' => ['id' => 5, 'title' => 'Danish', 'locale' => 'da_DK.UTF8'],
45  ];
46 
47  protected function ‪setUp(): void
48  {
49  parent::setUp();
50 
52  'acme-com',
53  $this->‪buildSiteConfiguration(1000, 'https://acme.com/'),
54  [
55  $this->‪buildDefaultLanguageConfiguration('EN', '/'),
56  $this->‪buildLanguageConfiguration('DE', '/de'),
57  $this->‪buildLanguageConfiguration('DE-CH', '/de-ch', ['DE'], 'fallback'),
58  $this->‪buildLanguageConfiguration('NL', '/nl'),
59  $this->‪buildLanguageConfiguration('FR', '/fr'),
60  $this->‪buildLanguageConfiguration('DA', '/da', ['EN'], 'free'),
61  ]
62  );
63 
64  $this->withDatabaseSnapshot(function () {
65  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
66  $backendUser = $this->setUpBackendUser(1);
67  ‪$GLOBALS['LANG'] = $this->get(LanguageServiceFactory::class)->createFromUserPreferences($backendUser);
68  $factory = DataHandlerFactory::fromYamlFile(__DIR__ . '/../Fixtures/HrefLangScenario.yml');
69  $writer = DataHandlerWriter::withBackendUser($backendUser);
70  $writer->invokeFactory($factory);
71  static::failIfArrayIsNotEmpty($writer->getErrors());
72  });
73  }
74 
75  #[DataProvider('checkHrefLangOutputDataProvider')]
76  #[Test]
77  public function ‪checkHrefLangOutput(string ‪$url, array $expectedTags, array $notExpectedTags): void
78  {
79  $this->setUpFrontendRootPage(
80  1000,
81  ['EXT:seo/Tests/Functional/Fixtures/HrefLang.typoscript']
82  );
83 
84  $response = $this->executeFrontendSubRequest(
85  new InternalRequest(‪$url)
86  );
87  $stream = $response->getBody();
88  $stream->rewind();
89  $content = $stream->getContents();
90 
91  foreach ($expectedTags as $expectedTag) {
92  self::assertStringContainsString($expectedTag, $content);
93  }
94 
95  foreach ($notExpectedTags as $notExpectedTag) {
96  self::assertStringNotContainsString($notExpectedTag, $content);
97  }
98  }
99 
100  public static function ‪checkHrefLangOutputDataProvider(): array
101  {
102  return [
103  'No translation available, so only hreflang tags expected for default language and fallback languages' => [
104  'https://acme.com/',
105  [
106  '<link rel="alternate" hreflang="en-US" href="https://acme.com/"/>',
107  '<link rel="alternate" hreflang="de-CH" href="https://acme.com/de-ch/"/>',
108  ],
109  [
110  '<link rel="alternate" hreflang="de-DE"',
111  ],
112  ],
113  'English page, with German translation' => [
114  'https://acme.com/hello',
115  [
116  '<link rel="alternate" hreflang="en-US" href="https://acme.com/hello"/>',
117  '<link rel="alternate" hreflang="de-DE" href="https://acme.com/de/willkommen"/>',
118  '<link rel="alternate" hreflang="x-default" href="https://acme.com/hello"/>',
119  ],
120  [],
121  ],
122  'German page, with English translation and English default' => [
123  'https://acme.com/de/willkommen',
124  [
125  '<link rel="alternate" hreflang="en-US" href="https://acme.com/hello"/>',
126  '<link rel="alternate" hreflang="de-DE" href="https://acme.com/de/willkommen"/>',
127  '<link rel="alternate" hreflang="x-default" href="https://acme.com/hello"/>',
128  ],
129  [],
130  ],
131  'English page, with German and Dutch translation, without Dutch hreflang config' => [
132  'https://acme.com/hello',
133  [
134  '<link rel="alternate" hreflang="en-US" href="https://acme.com/hello"/>',
135  '<link rel="alternate" hreflang="de-DE" href="https://acme.com/de/willkommen"/>',
136  '<link rel="alternate" hreflang="x-default" href="https://acme.com/hello"/>',
137  ],
138  [
139  '<link rel="alternate" hreflang="en-US" href="https://acme.com/nl/welkom"/>',
140  '<link rel="alternate" hreflang="" href="https://acme.com/nl/welkom"/>',
141  ],
142  ],
143  'Dutch page, with German and English translation, without Dutch hreflang config' => [
144  'https://acme.com/hello',
145  [
146  '<link rel="alternate" hreflang="en-US" href="https://acme.com/hello"/>',
147  '<link rel="alternate" hreflang="de-DE" href="https://acme.com/de/willkommen"/>',
148  '<link rel="alternate" hreflang="x-default" href="https://acme.com/hello"/>',
149  ],
150  [
151  '<link rel="alternate" hreflang="en-US" href="https://acme.com/nl/welkom"/>',
152  '<link rel="alternate" hreflang="" href="https://acme.com/nl/welkom"/>',
153  ],
154  ],
155  'English page with canonical' => [
156  'https://acme.com/contact',
157  [
158  '<link rel="alternate" hreflang="de-DE" href="https://acme.com/de/kontakt"/>',
159  '<link rel="alternate" hreflang="de-CH" href="https://acme.com/de-ch/kontakt"/>',
160  ],
161  [
162  '<link rel="alternate" hreflang="en-US" href="https://acme.com/contact"/>',
163  '<link rel="alternate" hreflang="x-default" href="https://acme.com/contact"/>',
164  ],
165  ],
166  'Swiss german page with canonical' => [
167  'https://acme.com/de-ch/uber',
168  [
169  '<link rel="alternate" hreflang="en-US" href="https://acme.com/about"/>',
170  '<link rel="alternate" hreflang="x-default" href="https://acme.com/about"/>',
171  '<link rel="alternate" hreflang="de-DE" href="https://acme.com/de/uber"/>',
172  ],
173  [
174  '<link rel="alternate" hreflang="de-CH" href="https://acme.com/de-ch/uber"/>',
175  ],
176  ],
177  'Swiss german page with fallback to German, without content' => [
178  'https://acme.com/de-ch/produkte',
179  [
180  '<link rel="alternate" hreflang="en-US" href="https://acme.com/products"/>',
181  '<link rel="alternate" hreflang="x-default" href="https://acme.com/products"/>',
182  '<link rel="alternate" hreflang="de-DE" href="https://acme.com/de/produkte"/>',
183  '<link rel="alternate" hreflang="de-CH" href="https://acme.com/de-ch/produkte"/>',
184  ],
185  [],
186  ],
187  'Languages with fallback should have hreflang even when page record is not translated, strict languages without translations shouldnt' => [
188  'https://acme.com/hello',
189  [
190  '<link rel="alternate" hreflang="de-CH" href="https://acme.com/de-ch/willkommen"/>',
191  ],
192  [
193  '<link rel="alternate" hreflang="fr-FR"',
194  ],
195  ],
196  'Pages with disabled hreflang generation should not render any hreflang tag' => [
197  'https://acme.com/no-hreflang',
198  [],
199  [
200  '<link rel="alternate" hreflang="',
201  ],
202  ],
203  'Translated pages with disabled hreflang generation in original language should not render any hreflang tag' => [
204  'https://acme.com/de/kein-hreflang',
205  [],
206  [
207  '<link rel="alternate" hreflang="',
208  ],
209  ],
210  'Languages with fallback type free should not have hreflang when page record is not translated' => [
211  'https://acme.com/no-translation',
212  [],
213  [
214  '<link rel="alternate" hreflang="',
215  ],
216  ],
217  ];
218  }
219 
220  protected static function ‪failIfArrayIsNotEmpty(array $items): void
221  {
222  if (empty($items)) {
223  return;
224  }
225 
226  self::fail(
227  'Array was not empty as expected, but contained these items:' . LF
228  . '* ' . implode(LF . '* ', $items)
229  );
230  }
231 }
‪TYPO3\CMS\Core\Localization\LanguageServiceFactory
Definition: LanguageServiceFactory.php:25
‪TYPO3\CMS\Seo\Tests\Functional\HrefLang\HrefLangGeneratorTest\LANGUAGE_PRESETS
‪const LANGUAGE_PRESETS
Definition: HrefLangGeneratorTest.php:37
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildLanguageConfiguration
‪buildLanguageConfiguration(string $identifier, string $base, array $fallbackIdentifiers=[], string $fallbackType=null)
Definition: SiteBasedTestTrait.php:108
‪TYPO3\CMS\Seo\Tests\Functional\HrefLang\HrefLangGeneratorTest
Definition: HrefLangGeneratorTest.php:30
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait
Definition: SiteBasedTestTrait.php:37
‪TYPO3\CMS\Seo\Tests\Functional\HrefLang
Definition: HrefLangGeneratorTest.php:18
‪TYPO3\CMS\Seo\Tests\Functional\HrefLang\HrefLangGeneratorTest\checkHrefLangOutput
‪checkHrefLangOutput(string $url, array $expectedTags, array $notExpectedTags)
Definition: HrefLangGeneratorTest.php:76
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\writeSiteConfiguration
‪writeSiteConfiguration(string $identifier, array $site=[], array $languages=[], array $errorHandling=[])
Definition: SiteBasedTestTrait.php:50
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildSiteConfiguration
‪buildSiteConfiguration(int $rootPageId, string $base='')
Definition: SiteBasedTestTrait.php:88
‪TYPO3\CMS\Seo\Tests\Functional\HrefLang\HrefLangGeneratorTest\failIfArrayIsNotEmpty
‪static failIfArrayIsNotEmpty(array $items)
Definition: HrefLangGeneratorTest.php:219
‪TYPO3\CMS\Seo\Tests\Functional\HrefLang\HrefLangGeneratorTest\checkHrefLangOutputDataProvider
‪static checkHrefLangOutputDataProvider()
Definition: HrefLangGeneratorTest.php:99
‪TYPO3\CMS\Webhooks\Message\$url
‪identifier readonly UriInterface $url
Definition: LoginErrorOccurredMessage.php:36
‪TYPO3\CMS\Seo\Tests\Functional\HrefLang\HrefLangGeneratorTest\$coreExtensionsToLoad
‪array $coreExtensionsToLoad
Definition: HrefLangGeneratorTest.php:32
‪TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait\buildDefaultLanguageConfiguration
‪buildDefaultLanguageConfiguration(string $identifier, string $base)
Definition: SiteBasedTestTrait.php:98
‪TYPO3\CMS\Seo\Tests\Functional\HrefLang\HrefLangGeneratorTest\setUp
‪setUp()
Definition: HrefLangGeneratorTest.php:46
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25