init
This commit is contained in:
+458
@@ -0,0 +1,458 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Esun3d\LanguageUrlStoreResolver\Test\Unit\Plugin;
|
||||
|
||||
use Magento\Framework\App\FrontControllerInterface;
|
||||
use Magento\Framework\App\Request\Http as HttpRequest;
|
||||
use Magento\Framework\App\Response\Http as HttpResponse;
|
||||
use Magento\Store\Model\Store;
|
||||
use Magento\Store\Model\StoreManagerInterface;
|
||||
use Magento\Store\Model\Website;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Esun3d\LanguageUrlStoreResolver\Model\Config;
|
||||
use Esun3d\LanguageUrlStoreResolver\Model\LanguageResolver;
|
||||
use Esun3d\LanguageUrlStoreResolver\Model\MarketCookie;
|
||||
use Esun3d\LanguageUrlStoreResolver\Model\MarketResolver;
|
||||
use Esun3d\LanguageUrlStoreResolver\Model\RequestPathProcessor;
|
||||
use Esun3d\LanguageUrlStoreResolver\Model\StoreCodeMapper;
|
||||
use Esun3d\LanguageUrlStoreResolver\Model\StoreViewRegistry;
|
||||
use Esun3d\LanguageUrlStoreResolver\Plugin\LanguageUrlFrontControllerPlugin;
|
||||
|
||||
class LanguageUrlFrontControllerPluginTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider productPathStoreProvider
|
||||
*/
|
||||
public function testSetsStoreAndStripsLanguageForProductPage(
|
||||
string $pathInfo,
|
||||
?string $market,
|
||||
string $expectedStoreCode,
|
||||
string $expectedPath
|
||||
): void {
|
||||
$config = $this->createConfig();
|
||||
$request = $this->createRequest($pathInfo, null);
|
||||
$request->expects(self::once())->method('setPathInfo')->with($expectedPath);
|
||||
$request->expects(self::exactly(3))->method('setParam');
|
||||
$request->expects(self::exactly(3))->method('setAlias');
|
||||
|
||||
$storeManager = $this->createMock(StoreManagerInterface::class);
|
||||
$storeManager->expects(self::once())->method('setCurrentStore')->with($expectedStoreCode);
|
||||
|
||||
$plugin = $this->createPlugin($config, $market, $storeManager);
|
||||
$proceedCalled = false;
|
||||
|
||||
$plugin->aroundDispatch(
|
||||
$this->createMock(FrontControllerInterface::class),
|
||||
function (HttpRequest $passedRequest) use (&$proceedCalled, $request) {
|
||||
$proceedCalled = true;
|
||||
self::assertSame($request, $passedRequest);
|
||||
|
||||
return 'proceeded';
|
||||
},
|
||||
$request
|
||||
);
|
||||
|
||||
self::assertTrue($proceedCalled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public static function productPathStoreProvider(): array
|
||||
{
|
||||
return [
|
||||
'english product path without cookie uses language default' => ['/en/product-a', null, 'en_US', '/product-a'],
|
||||
'english product path in DE market cookie' => ['/en/product-a', 'en_DE', 'en_DE', '/product-a'],
|
||||
'german product path without cookie uses language default' => ['/de/product-a', null, 'de_US', '/product-a'],
|
||||
'german product path in DE market cookie' => ['/de/product-a', 'de_DE', 'de_DE', '/product-a'],
|
||||
'german customer path uses the same language resolver' => [
|
||||
'/de/customer/account/login',
|
||||
null,
|
||||
'de_US',
|
||||
'/customer/account/login',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider realStoreCodeRedirectProvider
|
||||
*/
|
||||
public function testRedirectsRealStoreCodeUrl(string $pathInfo, string $expectedUrl): void
|
||||
{
|
||||
$config = $this->createConfig();
|
||||
$request = $this->createRequest($pathInfo, null);
|
||||
$request->method('getRequestUri')->willReturn($pathInfo);
|
||||
$request->method('getBaseUrl')->willReturn('');
|
||||
|
||||
$response = $this->createResponse($expectedUrl, 301);
|
||||
$marketCookie = $this->createMock(MarketCookie::class);
|
||||
$marketCookie->expects(self::once())->method('set');
|
||||
$storeManager = $this->createMock(StoreManagerInterface::class);
|
||||
$storeManager->expects(self::never())->method('setCurrentStore');
|
||||
|
||||
$plugin = $this->createPlugin($config, null, $storeManager, $marketCookie, $response);
|
||||
$proceedCalled = false;
|
||||
$result = $plugin->aroundDispatch(
|
||||
$this->createMock(FrontControllerInterface::class),
|
||||
function () use (&$proceedCalled) {
|
||||
$proceedCalled = true;
|
||||
},
|
||||
$request
|
||||
);
|
||||
|
||||
self::assertSame($response, $result);
|
||||
self::assertFalse($proceedCalled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public static function realStoreCodeRedirectProvider(): array
|
||||
{
|
||||
return [
|
||||
'english DE store code' => ['/en_DE/product-a', '/en/product-a'],
|
||||
'german DE store code' => ['/de_DE/product-a', '/de/product-a'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider marketRedirectProvider
|
||||
*/
|
||||
public function testRedirectsMarketSwitchUrl(string $pathInfo, string $market, string $expectedUrl): void
|
||||
{
|
||||
$config = $this->createConfig();
|
||||
$request = $this->createRequest($pathInfo, $market);
|
||||
$request->method('getRequestUri')->willReturn($pathInfo . '?market=' . $market);
|
||||
$request->method('getBaseUrl')->willReturn('');
|
||||
|
||||
$response = $this->createResponse($expectedUrl, 302);
|
||||
$marketCookie = $this->createMock(MarketCookie::class);
|
||||
$marketCookie->expects(self::once())->method('set')->with($market);
|
||||
$storeManager = $this->createMock(StoreManagerInterface::class);
|
||||
$storeManager->expects(self::never())->method('setCurrentStore');
|
||||
|
||||
$plugin = $this->createPlugin($config, null, $storeManager, $marketCookie, $response);
|
||||
$proceedCalled = false;
|
||||
$result = $plugin->aroundDispatch(
|
||||
$this->createMock(FrontControllerInterface::class),
|
||||
function () use (&$proceedCalled) {
|
||||
$proceedCalled = true;
|
||||
},
|
||||
$request
|
||||
);
|
||||
|
||||
self::assertSame($response, $result);
|
||||
self::assertFalse($proceedCalled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public static function marketRedirectProvider(): array
|
||||
{
|
||||
return [
|
||||
'english URL switches to german DE store' => ['/en/', 'de_DE', '/de/'],
|
||||
'english URL stays english DE store' => ['/en/', 'en_DE', '/en/'],
|
||||
'german URL stays german US store' => ['/de/', 'de_US', '/de/'],
|
||||
'root URL switches to german DE store' => ['/', 'de_DE', '/de/'],
|
||||
'root URL switches to english DE store' => ['/', 'en_DE', '/en/'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider skippedPathProvider
|
||||
*/
|
||||
public function testSkippedPathsAreNotProcessed(string $pathInfo): void
|
||||
{
|
||||
$config = $this->createConfig();
|
||||
$request = $this->createRequest($pathInfo, null);
|
||||
$storeManager = $this->createMock(StoreManagerInterface::class);
|
||||
$storeManager->expects(self::never())->method('setCurrentStore');
|
||||
|
||||
$plugin = $this->createPlugin($config, null, $storeManager);
|
||||
$proceedCalled = false;
|
||||
$result = $plugin->aroundDispatch(
|
||||
$this->createMock(FrontControllerInterface::class),
|
||||
function () use (&$proceedCalled) {
|
||||
$proceedCalled = true;
|
||||
|
||||
return 'skipped';
|
||||
},
|
||||
$request
|
||||
);
|
||||
|
||||
self::assertSame('skipped', $result);
|
||||
self::assertTrue($proceedCalled);
|
||||
}
|
||||
|
||||
public function testInvalidMarketParamDoesNotSetCurrentStore(): void
|
||||
{
|
||||
$config = $this->createConfig();
|
||||
$request = $this->createRequest('/en/product-a', 'fr_FR');
|
||||
$storeManager = $this->createMock(StoreManagerInterface::class);
|
||||
$storeManager->expects(self::never())->method('setCurrentStore');
|
||||
|
||||
$plugin = $this->createPlugin($config, null, $storeManager);
|
||||
$result = $plugin->aroundDispatch(
|
||||
$this->createMock(FrontControllerInterface::class),
|
||||
static function () {
|
||||
return 'invalid-market-proceeded';
|
||||
},
|
||||
$request
|
||||
);
|
||||
|
||||
self::assertSame('invalid-market-proceeded', $result);
|
||||
}
|
||||
|
||||
public function testRootPathForcesWebsiteDefaultStore(): void
|
||||
{
|
||||
$config = $this->createConfig();
|
||||
$request = $this->createRequest('/', null);
|
||||
$request->expects(self::exactly(2))->method('setParam');
|
||||
$request->expects(self::exactly(2))->method('setAlias');
|
||||
|
||||
$defaultStore = $this->createMock(Store::class);
|
||||
$defaultStore->method('isActive')->willReturn(true);
|
||||
$defaultStore->method('getCode')->willReturn('en_US');
|
||||
|
||||
$website = $this->createMock(Website::class);
|
||||
$website->method('getDefaultStore')->willReturn($defaultStore);
|
||||
|
||||
$storeManager = $this->createMock(StoreManagerInterface::class);
|
||||
$storeManager->method('getWebsite')->willReturn($website);
|
||||
$storeManager->expects(self::once())->method('setCurrentStore')->with('en_US');
|
||||
|
||||
$marketCookie = $this->createMock(MarketCookie::class);
|
||||
$marketCookie->expects(self::once())->method('set')->with('en_US');
|
||||
|
||||
$plugin = $this->createPlugin($config, 'ja_JP', $storeManager, $marketCookie);
|
||||
$result = $plugin->aroundDispatch(
|
||||
$this->createMock(FrontControllerInterface::class),
|
||||
static function () {
|
||||
return 'root-proceeded';
|
||||
},
|
||||
$request
|
||||
);
|
||||
|
||||
self::assertSame('root-proceeded', $result);
|
||||
}
|
||||
|
||||
public function testUnprefixedContentPathForcesWebsiteDefaultStore(): void
|
||||
{
|
||||
$config = $this->createConfig();
|
||||
$request = $this->createRequest('/product-a.html', null);
|
||||
$request->expects(self::exactly(2))->method('setParam');
|
||||
$request->expects(self::exactly(2))->method('setAlias');
|
||||
|
||||
$defaultStore = $this->createMock(Store::class);
|
||||
$defaultStore->method('isActive')->willReturn(true);
|
||||
$defaultStore->method('getCode')->willReturn('en_US');
|
||||
|
||||
$website = $this->createMock(Website::class);
|
||||
$website->method('getDefaultStore')->willReturn($defaultStore);
|
||||
|
||||
$storeManager = $this->createMock(StoreManagerInterface::class);
|
||||
$storeManager->method('getWebsite')->willReturn($website);
|
||||
$storeManager->expects(self::once())->method('setCurrentStore')->with('en_US');
|
||||
|
||||
$marketCookie = $this->createMock(MarketCookie::class);
|
||||
$marketCookie->expects(self::once())->method('set')->with('en_US');
|
||||
|
||||
$plugin = $this->createPlugin($config, 'de_US', $storeManager, $marketCookie);
|
||||
$result = $plugin->aroundDispatch(
|
||||
$this->createMock(FrontControllerInterface::class),
|
||||
static function () {
|
||||
return 'unprefixed-product-proceeded';
|
||||
},
|
||||
$request
|
||||
);
|
||||
|
||||
self::assertSame('unprefixed-product-proceeded', $result);
|
||||
}
|
||||
|
||||
public function testCustomerAccountPathForcesWebsiteDefaultStoreWithoutLanguageContext(): void
|
||||
{
|
||||
$config = $this->createConfig();
|
||||
$request = $this->createRequest('/customer/account/login', null);
|
||||
$request->expects(self::exactly(2))->method('setParam');
|
||||
$request->expects(self::exactly(2))->method('setAlias');
|
||||
|
||||
$defaultStore = $this->createMock(Store::class);
|
||||
$defaultStore->method('isActive')->willReturn(true);
|
||||
$defaultStore->method('getCode')->willReturn('en_US');
|
||||
|
||||
$website = $this->createMock(Website::class);
|
||||
$website->method('getDefaultStore')->willReturn($defaultStore);
|
||||
|
||||
$storeManager = $this->createMock(StoreManagerInterface::class);
|
||||
$storeManager->method('getWebsite')->willReturn($website);
|
||||
$storeManager->expects(self::once())->method('setCurrentStore')->with('en_US');
|
||||
|
||||
$marketCookie = $this->createMock(MarketCookie::class);
|
||||
$marketCookie->expects(self::once())->method('set')->with('en_US');
|
||||
|
||||
$plugin = $this->createPlugin($config, null, $storeManager, $marketCookie);
|
||||
$result = $plugin->aroundDispatch(
|
||||
$this->createMock(FrontControllerInterface::class),
|
||||
static function () {
|
||||
return 'customer-login-proceeded';
|
||||
},
|
||||
$request
|
||||
);
|
||||
|
||||
self::assertSame('customer-login-proceeded', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public static function skippedPathProvider(): array
|
||||
{
|
||||
return [
|
||||
'static' => ['/static/version123/frontend/file.css'],
|
||||
'media' => ['/media/catalog/product/a.jpg'],
|
||||
'rest' => ['/rest/V1/products'],
|
||||
'graphql' => ['/graphql'],
|
||||
];
|
||||
}
|
||||
|
||||
private function createPlugin(
|
||||
Config $config,
|
||||
?string $cookieMarket,
|
||||
StoreManagerInterface $storeManager,
|
||||
?MarketCookie $marketCookie = null,
|
||||
?HttpResponse $response = null
|
||||
): LanguageUrlFrontControllerPlugin {
|
||||
$registry = $this->createRegistry();
|
||||
$scopeStoreManager = $this->createScopeStoreManager();
|
||||
$languageResolver = new LanguageResolver($registry, $scopeStoreManager);
|
||||
$marketCookie = $marketCookie ?: $this->createMock(MarketCookie::class);
|
||||
$marketCookie->method('get')->willReturn($cookieMarket);
|
||||
$storeCodeMapper = new StoreCodeMapper($registry, $scopeStoreManager);
|
||||
|
||||
return new LanguageUrlFrontControllerPlugin(
|
||||
$config,
|
||||
$languageResolver,
|
||||
new MarketResolver($marketCookie, $storeCodeMapper),
|
||||
$storeCodeMapper,
|
||||
new RequestPathProcessor($languageResolver),
|
||||
$storeManager,
|
||||
$marketCookie,
|
||||
$response ?: $this->createMock(HttpResponse::class),
|
||||
$this->createMock(LoggerInterface::class),
|
||||
$this->createMock(\Magento\Framework\Locale\ResolverInterface::class),
|
||||
$this->createMock(\Magento\Framework\App\Config\ScopeConfigInterface::class)
|
||||
);
|
||||
}
|
||||
|
||||
private function createConfig(): Config
|
||||
{
|
||||
$scopeConfig = $this->createMock(\Magento\Framework\App\Config\ScopeConfigInterface::class);
|
||||
$scopeConfig->method('isSetFlag')->willReturn(true);
|
||||
$scopeConfig->method('getValue')->willReturnCallback(static function (string $path, string $scope) {
|
||||
self::assertSame(\Magento\Store\Model\ScopeInterface::SCOPE_STORE, $scope);
|
||||
|
||||
$values = [
|
||||
'language_url_store_resolver/general/market_cookie_name' => 'market',
|
||||
'language_url_store_resolver/general/market_cookie_lifetime' => '2592000',
|
||||
];
|
||||
|
||||
return $values[$path] ?? null;
|
||||
});
|
||||
|
||||
return new Config($scopeConfig);
|
||||
}
|
||||
|
||||
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('getDefaultStoreCodeForLanguage')->willReturnCallback(
|
||||
static function (string $language): ?string {
|
||||
$map = [
|
||||
'en' => 'en_US',
|
||||
'de' => 'de_US',
|
||||
];
|
||||
|
||||
return $map[$language] ?? null;
|
||||
}
|
||||
);
|
||||
$registry->method('isLanguageInWebsite')->willReturnCallback(
|
||||
static fn(string $language, int $websiteId): bool =>
|
||||
$websiteId === 1 && in_array($language, ['en', 'de'], true)
|
||||
);
|
||||
$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('getStoreCodeForLanguageInWebsite')->willReturnCallback(
|
||||
static function (string $language, int $websiteId): ?string {
|
||||
if ($websiteId !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ['en' => 'en_US', 'de' => 'de_US'][$language] ?? null;
|
||||
}
|
||||
);
|
||||
|
||||
return $registry;
|
||||
}
|
||||
|
||||
private function createScopeStoreManager(): StoreManagerInterface
|
||||
{
|
||||
$defaultStore = $this->createMock(Store::class);
|
||||
$defaultStore->method('getCode')->willReturn('default_store');
|
||||
$website = $this->createMock(Website::class);
|
||||
$website->method('getId')->willReturn(1);
|
||||
$website->method('getDefaultStore')->willReturn($defaultStore);
|
||||
$storeManager = $this->createMock(StoreManagerInterface::class);
|
||||
$storeManager->method('getWebsite')->willReturn($website);
|
||||
|
||||
return $storeManager;
|
||||
}
|
||||
|
||||
private function createRequest(string $pathInfo, ?string $market): HttpRequest
|
||||
{
|
||||
$request = $this->getMockBuilder(HttpRequest::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['getPathInfo', 'getRequestUri', 'getBaseUrl', 'getParam', 'setPathInfo', 'setParam', 'setAlias'])
|
||||
->getMock();
|
||||
$request->method('getPathInfo')->willReturn($pathInfo);
|
||||
$request->method('getRequestUri')->willReturn($pathInfo);
|
||||
$request->method('getBaseUrl')->willReturn('');
|
||||
$request->method('getParam')->with('market')->willReturn($market);
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
private function createResponse(string $expectedUrl, int $expectedStatusCode): HttpResponse
|
||||
{
|
||||
$response = $this->getMockBuilder(HttpResponse::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods(['setRedirect'])
|
||||
->getMock();
|
||||
$response->expects(self::once())
|
||||
->method('setRedirect')
|
||||
->with($expectedUrl, $expectedStatusCode)
|
||||
->willReturnSelf();
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user