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

212 lines
7.7 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\LanguageResolver;
use Esun3d\LanguageUrlStoreResolver\Model\RequestPathProcessor;
use Esun3d\LanguageUrlStoreResolver\Model\StoreCodeMapper;
use Esun3d\LanguageUrlStoreResolver\Model\StoreViewRegistry;
class LanguageAndPathTest extends TestCase
{
/**
* @var StoreViewRegistry|\PHPUnit\Framework\MockObject\MockObject
*/
private $storeViewRegistry;
/** @var StoreManagerInterface|\PHPUnit\Framework\MockObject\MockObject */
private $storeManager;
protected function setUp(): void
{
$this->storeViewRegistry = $this->createMock(StoreViewRegistry::class);
$this->storeViewRegistry->method('isKnownLanguage')->willReturnCallback(static function (string $language): bool {
return in_array($language, ['en', 'de'], true);
});
$this->storeViewRegistry->method('isKnownStoreCode')->willReturnCallback(static function (string $storeCode): bool {
return in_array($storeCode, ['en_US', 'en_DE', 'de_US', 'de_DE'], true);
});
$this->storeViewRegistry->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;
});
$this->storeViewRegistry->method('getDefaultStoreCodeForLanguage')->willReturnCallback(
static function (string $language): ?string {
$map = [
'en' => 'en_US',
'de' => 'de_US',
];
return $map[$language] ?? null;
}
);
$this->storeViewRegistry->method('isLanguageInWebsite')->willReturnCallback(
static fn(string $language, int $websiteId): bool =>
$websiteId === 1 && in_array($language, ['en', 'de'], true)
);
$this->storeViewRegistry->method('isStoreCodeInWebsite')->willReturnCallback(
static fn(string $storeCode, int $websiteId): bool =>
$websiteId === 1 && in_array($storeCode, ['en_US', 'en_DE', 'de_US', 'de_DE'], true)
);
$this->storeViewRegistry->method('getStoreCodeForLanguageInWebsite')->willReturnCallback(
static function (string $language, int $websiteId): ?string {
if ($websiteId !== 1) {
return null;
}
return ['en' => 'en_US', 'de' => 'de_US'][$language] ?? null;
}
);
$defaultStore = $this->createMock(Store::class);
$defaultStore->method('getCode')->willReturn('en_US');
$website = $this->createMock(Website::class);
$website->method('getId')->willReturn(1);
$website->method('getDefaultStore')->willReturn($defaultStore);
$this->storeManager = $this->createMock(StoreManagerInterface::class);
$this->storeManager->method('getWebsite')->willReturn($website);
}
/**
* @dataProvider productPathProvider
*/
public function testResolvesLanguageFromProductPath(string $pathInfo, ?string $expectedLanguage): void
{
$resolver = new LanguageResolver($this->storeViewRegistry, $this->storeManager);
self::assertSame($expectedLanguage, $resolver->resolveFromPath($pathInfo));
}
/**
* @return mixed[]
*/
public static function productPathProvider(): array
{
return [
'english product path' => ['/en/product-a', 'en'],
'german product path' => ['/de/product-a', 'de'],
'english language root' => ['/en', 'en'],
'real store code is not language' => ['/en_US/product-a', null],
'unsupported prefix' => ['/fr/product-a', null],
];
}
/**
* @dataProvider stripProductPathProvider
*/
public function testStripsLanguagePrefixBeforeUrlRewrite(string $pathInfo, string $expectedPathInfo): void
{
$processor = new RequestPathProcessor(new LanguageResolver($this->storeViewRegistry, $this->storeManager));
self::assertSame($expectedPathInfo, $processor->stripLanguagePrefix($pathInfo));
}
/**
* @return mixed[]
*/
public static function stripProductPathProvider(): array
{
return [
'english product path' => ['/en/product-a', '/product-a'],
'german product path' => ['/de/product-a', '/product-a'],
'nested product path' => ['/de/category/product-a', '/category/product-a'],
'language root' => ['/en', '/'],
'non language path unchanged' => ['/product-a', '/product-a'],
];
}
/**
* @dataProvider replaceProductPathProvider
*/
public function testReplacesLanguagePrefixForMarketSwitch(string $pathInfo, string $language, string $expectedPathInfo): void
{
$processor = new RequestPathProcessor(new LanguageResolver($this->storeViewRegistry, $this->storeManager));
self::assertSame($expectedPathInfo, $processor->replaceLanguagePrefix($pathInfo, $language));
}
/**
* @return mixed[]
*/
public static function replaceProductPathProvider(): array
{
return [
'german product path switches to english' => [
'/de/privacy-policy-cookie-restriction-mode/',
'en',
'/en/privacy-policy-cookie-restriction-mode/',
],
'english product path switches to german' => [
'/en/product-a',
'de',
'/de/product-a',
],
'language root keeps trailing slash' => [
'/de/',
'en',
'/en/',
],
];
}
/**
* @dataProvider storeMappingProvider
*/
public function testMapsProductPathLanguageAndMarketToRealStoreCode(
string $language,
?string $market,
?string $expectedStoreCode
): void {
$mapper = new StoreCodeMapper($this->storeViewRegistry, $this->storeManager);
self::assertSame($expectedStoreCode, $mapper->map($language, $market));
}
/**
* @return mixed[]
*/
public static function storeMappingProvider(): array
{
return [
'english US product path' => ['en', 'en_US', 'en_US'],
'english DE product path' => ['en', 'en_DE', 'en_DE'],
'german US product path' => ['de', 'de_US', 'de_US'],
'german DE product path' => ['de', 'de_DE', 'de_DE'],
'english path ignores german market and uses default' => ['en', 'de_DE', 'en_US'],
'unknown language has no default' => ['fr', null, null],
];
}
public function testUsesLanguageSpecificDefaultStoreFromRegistry(): void
{
$mapper = new StoreCodeMapper($this->storeViewRegistry, $this->storeManager);
self::assertSame('en_US', $mapper->getDefaultStoreCodeForLanguage('en'));
self::assertSame('de_US', $mapper->getDefaultStoreCodeForLanguage('de'));
}
public function testUsesCurrentWebsiteWhenLanguageExistsInMultipleWebsites(): void
{
$registry = $this->createMock(StoreViewRegistry::class);
$registry->expects(self::once())
->method('getStoreCodeForLanguageInWebsite')
->with('de', 1)
->willReturn('de_EU');
$mapper = new StoreCodeMapper($registry, $this->storeManager);
self::assertSame('de_EU', $mapper->getDefaultStoreCodeForLanguage('de'));
}
}