Files
2026-09-15 10:35:56 +08:00

197 lines
6.9 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun3d\LanguageUrlStoreResolver\Test\Unit\Model;
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Store\Model\Website;
use PHPUnit\Framework\TestCase;
use Esun3d\LanguageUrlStoreResolver\Model\Config;
use Esun3d\LanguageUrlStoreResolver\Model\StoreCodeMapper;
use Esun3d\LanguageUrlStoreResolver\Model\StoreViewRegistry;
use Esun3d\LanguageUrlStoreResolver\Model\UrlPathConverter;
class UrlPathConverterTest extends TestCase
{
/**
* @dataProvider productUrlProvider
*/
public function testConvertsGeneratedProductUrlsToLanguageUrls(
string $url,
string $language,
string $expectedUrl
): void {
$converter = new UrlPathConverter(
$this->createConfig(),
new StoreCodeMapper($this->createRegistry(), $this->createStoreManager('https://example.com/')),
$this->createRegistry(),
$this->createStoreManager('https://example.com/')
);
self::assertSame($expectedUrl, $converter->toLanguageUrl($url, $language));
}
/**
* @return mixed[]
*/
public static function productUrlProvider(): array
{
return [
'real english US store code product url' => [
'https://example.com/en_US/product-a',
'en',
'https://example.com/en/product-a',
],
'real german DE store code product url' => [
'https://example.com/de_DE/product-a',
'de',
'https://example.com/de/product-a',
],
'plain product url gets language prefix' => [
'https://example.com/product-a',
'en',
'https://example.com/en/product-a',
],
'language product url is not duplicated' => [
'https://example.com/en/product-a',
'en',
'https://example.com/en/product-a',
],
'query and fragment survive conversion' => [
'https://example.com/en_US/product-a?q=printer#reviews',
'en',
'https://example.com/en/product-a?q=printer#reviews',
],
];
}
public function testSkipsExternalProductUrl(): void
{
$converter = new UrlPathConverter(
$this->createConfig(),
new StoreCodeMapper($this->createRegistry(), $this->createStoreManager('https://example.com/')),
$this->createRegistry(),
$this->createStoreManager('https://example.com/')
);
self::assertSame(
'https://cdn.example.net/en_US/product-a',
$converter->toLanguageUrl('https://cdn.example.net/en_US/product-a', 'en')
);
}
public function testSkipsStaticProductAssetPath(): void
{
$converter = new UrlPathConverter(
$this->createConfig(),
new StoreCodeMapper($this->createRegistry(), $this->createStoreManager('https://example.com/')),
$this->createRegistry(),
$this->createStoreManager('https://example.com/')
);
self::assertSame(
'https://example.com/static/version123/frontend/product-a.jpg',
$converter->toLanguageUrl('https://example.com/static/version123/frontend/product-a.jpg', 'en')
);
}
public function testOmitsPrefixForWebsiteDefaultLanguage(): void
{
$mapper = $this->createMock(StoreCodeMapper::class);
$mapper->method('isRealStoreCodeInScope')->with('en_US')->willReturn(true);
$mapper->method('languageFromStoreCode')->with('en_US')->willReturn('en');
$mapper->method('isLanguageAllowed')->willReturn(false);
$mapper->method('isDefaultLanguage')->with('en')->willReturn(true);
$converter = new UrlPathConverter(
$this->createConfig(),
$mapper,
$this->createRegistry(),
$this->createStoreManager('https://example.com/')
);
self::assertSame(
'https://example.com/product-a',
$converter->toLanguageUrl('https://example.com/en_US/product-a', 'en')
);
}
private function createConfig(): Config
{
$config = $this->createMock(Config::class);
$config->method('shouldSkipPath')->willReturnCallback(static function (string $path): bool {
$path = strtolower(trim($path, '/'));
$skipPrefixes = [
'admin',
'rest',
'graphql',
'soap',
'static',
'media',
'pub',
'customer/section/load',
];
foreach ($skipPrefixes as $prefix) {
if ($path === $prefix || strpos($path, $prefix . '/') === 0) {
return true;
}
}
return false;
});
return $config;
}
private function createRegistry(): StoreViewRegistry
{
$registry = $this->createMock(StoreViewRegistry::class);
$registry->method('isKnownLanguage')->willReturnCallback(static function (string $language): bool {
return in_array($language, ['en', 'de'], true);
});
$registry->method('isKnownStoreCode')->willReturnCallback(static function (string $storeCode): bool {
return in_array($storeCode, ['en_US', 'en_DE', 'de_US', 'de_DE'], true);
});
$registry->method('getLanguageByStoreCode')->willReturnCallback(static function (string $storeCode): ?string {
$map = [
'en_US' => 'en',
'en_DE' => 'en',
'de_US' => 'de',
'de_DE' => 'de',
];
return $map[$storeCode] ?? null;
});
$registry->method('isStoreCodeInWebsite')->willReturnCallback(
static fn(string $storeCode, int $websiteId): bool =>
$websiteId === 1 && in_array($storeCode, ['en_US', 'en_DE', 'de_US', 'de_DE'], true)
);
$registry->method('isLanguageInWebsite')->willReturnCallback(
static fn(string $language, int $websiteId): bool =>
$websiteId === 1 && in_array($language, ['en', 'de'], true)
);
return $registry;
}
private function createStoreManager(string $baseUrl): StoreManagerInterface
{
$store = $this->getMockBuilder(Store::class)
->disableOriginalConstructor()
->onlyMethods(['getBaseUrl'])
->getMock();
$store->method('getBaseUrl')->willReturn($baseUrl);
$storeManager = $this->createMock(StoreManagerInterface::class);
$storeManager->method('getStore')->willReturn($store);
$website = $this->createMock(Website::class);
$website->method('getId')->willReturn(1);
$website->method('getDefaultStore')->willReturn($store);
$storeManager->method('getWebsite')->willReturn($website);
return $storeManager;
}
}