diff --git a/Build/phpstan/Core12/phpstan-baseline.neon b/Build/phpstan/Core12/phpstan-baseline.neon index 5e2a265a..f10b4578 100644 --- a/Build/phpstan/Core12/phpstan-baseline.neon +++ b/Build/phpstan/Core12/phpstan-baseline.neon @@ -335,6 +335,56 @@ parameters: count: 1 path: ../../../Tests/Functional/Regression/LocalizationInlineRegressionTest.php + - + message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\PreviewTranslationInformationTest\\:\\:buildDefaultLanguageConfiguration\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/PreviewTranslationInformationTest.php + + - + message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\PreviewTranslationInformationTest\\:\\:buildErrorHandlingConfiguration\\(\\) has parameter \\$codes with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/PreviewTranslationInformationTest.php + + - + message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\PreviewTranslationInformationTest\\:\\:buildErrorHandlingConfiguration\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/PreviewTranslationInformationTest.php + + - + message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\PreviewTranslationInformationTest\\:\\:buildLanguageConfiguration\\(\\) has parameter \\$fallbackIdentifiers with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/PreviewTranslationInformationTest.php + + - + message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\PreviewTranslationInformationTest\\:\\:buildLanguageConfiguration\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/PreviewTranslationInformationTest.php + + - + message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\PreviewTranslationInformationTest\\:\\:failIfArrayIsNotEmpty\\(\\) has parameter \\$items with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/PreviewTranslationInformationTest.php + + - + message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\PreviewTranslationInformationTest\\:\\:mergeSiteConfiguration\\(\\) has parameter \\$overrides with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/PreviewTranslationInformationTest.php + + - + message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\PreviewTranslationInformationTest\\:\\:writeSiteConfiguration\\(\\) has parameter \\$errorHandling with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/PreviewTranslationInformationTest.php + + - + message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\PreviewTranslationInformationTest\\:\\:writeSiteConfiguration\\(\\) has parameter \\$languages with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/PreviewTranslationInformationTest.php + + - + message: "#^Method WebVision\\\\Deepltranslate\\\\Core\\\\Tests\\\\Functional\\\\Regression\\\\PreviewTranslationInformationTest\\:\\:writeSiteConfiguration\\(\\) has parameter \\$site with no value type specified in iterable type array\\.$#" + count: 1 + path: ../../../Tests/Functional/Regression/PreviewTranslationInformationTest.php + - message: "#^Cannot access property \\$code on DeepL\\\\Language\\|null\\.$#" count: 7 diff --git a/Build/phpstan/Core12/phpstan.neon b/Build/phpstan/Core12/phpstan.neon index 85b91ad8..f85bac56 100644 --- a/Build/phpstan/Core12/phpstan.neon +++ b/Build/phpstan/Core12/phpstan.neon @@ -16,7 +16,10 @@ parameters: - ../../../.Build/* - ../../../Tests/Functional/Updates/Fixtures/Extension/test_extension/ext_emconf.php - ../../../Tests/Functional/Fixtures/Extensions/test_services_override/ext_emconf.php + - ../../../Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/ext_emconf.php typo3: contextApiGetAspectMapping: 'frontend.preview': TYPO3\CMS\Frontend\Aspect\PreviewAspect + requestGetAttributeMapping: + 'typo3.testing.context': TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequestContext diff --git a/Build/phpunit/FunctionalTestsBootstrap.php b/Build/phpunit/FunctionalTestsBootstrap.php index a95bc520..5ee93da5 100644 --- a/Build/phpunit/FunctionalTestsBootstrap.php +++ b/Build/phpunit/FunctionalTestsBootstrap.php @@ -23,6 +23,30 @@ * before instantiating the test suites. */ (static function () { + /** + * @todo Fix testing-framework extension package information loading within the framework and remove workaround + * here after upgrade to testing-framework release containing the fix. + */ + $frameworkExtension = [ + 'Resources/Core/Functional/Extensions/json_response', + 'Resources/Core/Functional/Extensions/private_container', + ]; + $composerPackageManager = new \TYPO3\TestingFramework\Composer\ComposerPackageManager(); + $testingFrameworkPath = $composerPackageManager->getPackageInfo('typo3/testing-framework')->getRealPath(); + foreach ($frameworkExtension as $frameworkExtensionPath) { + $packageInfo = $composerPackageManager->getPackageInfoWithFallback(rtrim($testingFrameworkPath, '/') . '/' . $frameworkExtensionPath); + if ($packageInfo === null) { + throw new \RuntimeException( + sprintf( + 'Could not preload "typo3/testing-framework" extension "%s".', + basename($frameworkExtensionPath), + ), + 1734217315, + ); + } + } + + // Original typo3/testing-framework bootstrap $testbase = new \TYPO3\TestingFramework\Core\Testbase(); $testbase->defineOriginalRootPath(); $testbase->createDirectory(ORIGINAL_ROOT . 'typo3temp/var/tests'); diff --git a/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/Classes/Middleware/BackendUserHandler.php b/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/Classes/Middleware/BackendUserHandler.php new file mode 100644 index 00000000..1cc85a99 --- /dev/null +++ b/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/Classes/Middleware/BackendUserHandler.php @@ -0,0 +1,62 @@ +getAttribute('typo3.testing.context'); + $backendUserId = $internalRequestContext->getBackendUserId(); + $workspaceId = $internalRequestContext->getWorkspaceId() ?? 0; + + if ((int)$backendUserId === 0) { + // Skip if $backendUserId is invalid, typically null or 0 + return $handler->handle($request); + } + + $row = GeneralUtility::makeInstance(ConnectionPool::class) + ->getConnectionForTable('be_users') + ->select(['*'], 'be_users', ['uid' => $backendUserId]) + ->fetchAssociative(); + if ($row !== false) { + // Init backend user if found in database + $backendUser = GeneralUtility::makeInstance(FrontendBackendUserAuthentication::class); + $backendUser->user = $row; + $backendUser->uc = isset($row['uc']) ? unserialize($row['uc']) : []; + $backendUser->initializeUserSessionManager(); + $backendUser->setTemporaryWorkspace($workspaceId); + $GLOBALS['BE_USER'] = $backendUser; + $this->setBackendUserAspect(GeneralUtility::makeInstance(Context::class), $backendUser); + } + return $handler->handle($request); + } + + /** + * Register the backend user as aspect + */ + protected function setBackendUserAspect(Context $context, BackendUserAuthentication $user): void + { + $context->setAspect('backend.user', GeneralUtility::makeInstance(UserAspect::class, $user)); + $context->setAspect('workspace', GeneralUtility::makeInstance(WorkspaceAspect::class, $user->workspace)); + } +} diff --git a/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/Configuration/RequestMiddlewares.php b/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/Configuration/RequestMiddlewares.php new file mode 100644 index 00000000..7d023100 --- /dev/null +++ b/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/Configuration/RequestMiddlewares.php @@ -0,0 +1,19 @@ + [ + 'typo3/json-response/backend-user-authentication' => [ + /** + * Replace {@see \TYPO3\JsonResponse\Middleware\BackendUserHandler} as target here to incorporate + * `typo3/testing-framework` pull-request https://github.com/TYPO3/testing-framework/pull/536 as + * a workaround until resolved within testing-framework. + * + * @todo Remove test-fixture extension completely when fixed within typo3/testing-framework. Also requires + * temporary workaround in {@see Build/phpunit/FunctionalTestsBootstrap.php} to force framework + * extension loading to have have package information available - otherwise dependency ordering would + * not work. Needs to be resolved in the testing-framework. + */ + 'target' => \WebVision\TestingFrameworkBackendUserHandlerReplacement\Middleware\BackendUserHandler::class, + ], + ], +]; diff --git a/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/Configuration/Services.yaml b/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/Configuration/Services.yaml new file mode 100644 index 00000000..f0ea4711 --- /dev/null +++ b/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/Configuration/Services.yaml @@ -0,0 +1,8 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + WebVision\TestingFrameworkBackendUserHandlerReplacement\: + resource: '../Classes/*' diff --git a/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/composer.json b/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/composer.json new file mode 100644 index 00000000..9c7bcd07 --- /dev/null +++ b/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/composer.json @@ -0,0 +1,20 @@ +{ + "name": "web-vision/testing-framework-backenduserhandler-replacement", + "type": "typo3-cms-extension", + "description": "Change service registrations for testing purposes.", + "license": ["GPL-2.0-or-later"], + "extra": { + "typo3/cms": { + "extension-key": "testing_framework_backenduserhandler_replacement" + } + }, + "require": { + "typo3/cms-core": "12.*.*@dev || 13.*.*@dev", + "typo3/testing-json-response": "*" + }, + "autoload": { + "psr-4": { + "WebVision\\TestingFrameworkBackendUserHandlerReplacement\\": "Classes" + } + } +} diff --git a/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/ext_emconf.php b/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/ext_emconf.php new file mode 100644 index 00000000..73ccd10c --- /dev/null +++ b/Tests/Functional/Fixtures/Extensions/testing_framework_backenduserhandler_replacement/ext_emconf.php @@ -0,0 +1,22 @@ + 'TF BackendUserHandler replacement', + 'description' => 'TF BackendUserHandler replacement', + 'category' => 'example', + 'version' => '1.0.0', + 'state' => 'beta', + 'createDirs' => '', + 'clearCacheOnLoad' => 0, + 'author' => 'Stefan Bürk', + 'author_email' => 'stefan@buerk.tech', + 'author_company' => '', + 'constraints' => [ + 'depends' => [ + 'typo3' => '12.4.0-13.4.99', + 'json_response' => '*', + ], + 'conflicts' => [], + 'suggests' => [], + ], +]; diff --git a/Tests/Functional/Regression/Fixtures/PreviewTranslationInformation.csv b/Tests/Functional/Regression/Fixtures/PreviewTranslationInformation.csv new file mode 100644 index 00000000..cdc73348 --- /dev/null +++ b/Tests/Functional/Regression/Fixtures/PreviewTranslationInformation.csv @@ -0,0 +1,10 @@ +pages +,"uid","pid",doktype,"hidden","title",subtitle,"sys_language_uid","l10n_parent","slug","tx_wvdeepltranslate_content_not_checked","tx_wvdeepltranslate_translated_time" +,1,0,1,0,"Deepl-Functional-Test","",0,0,"/",0,0 +,2,0,1,0,"Artikel","",1,2,"//",0,0 +,3,1,1,0,"Articles","",0,0,"/articles/",0,0 +,4,1,1,1,"Artikel","",1,3,"/artikel/",1,1734104657 +"be_users" +,"uid","pid","tstamp","username","password","admin","disable","starttime","endtime","options","crdate","workspace_perms","deleted","TSconfig","lastlogin","workspace_id","db_mountpoints" +# The password is "password" +,1,0,1366642540,"admin","$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1",1,0,0,0,0,1366642540,1,0,,1371033743,0,1 diff --git a/Tests/Functional/Regression/Fixtures/PreviewTranslationInformation.typoscript b/Tests/Functional/Regression/Fixtures/PreviewTranslationInformation.typoscript new file mode 100644 index 00000000..e184cfa0 --- /dev/null +++ b/Tests/Functional/Regression/Fixtures/PreviewTranslationInformation.typoscript @@ -0,0 +1,9 @@ +page = PAGE +page.100 = CONTENT +page.100 { + table = tt_content + select { + orderBy = sorting + where = {#colPos}=0 + } +} diff --git a/Tests/Functional/Regression/PreviewTranslationInformationTest.php b/Tests/Functional/Regression/PreviewTranslationInformationTest.php new file mode 100644 index 00000000..ca58e894 --- /dev/null +++ b/Tests/Functional/Regression/PreviewTranslationInformationTest.php @@ -0,0 +1,130 @@ + [ + 'id' => 0, + 'title' => 'English', + 'locale' => 'en_US.UTF-8', + 'iso' => 'en', + 'hrefLang' => 'en-US', + 'direction' => '', + 'custom' => [ + 'deeplTargetLanguage' => '', + 'deeplAllowedAutoTranslate' => false, + 'deeplAllowedReTranslate' => false, + ], + ], + 'DE' => [ + 'id' => 1, + 'title' => 'Deutsch', + 'locale' => 'de_DE', + 'iso' => 'de', + 'hrefLang' => 'de-DE', + 'direction' => '', + 'custom' => [ + 'deeplTargetLanguage' => 'DE', + 'deeplAllowedAutoTranslate' => true, + 'deeplAllowedReTranslate' => true, + ], + ], + ]; + + protected array $configurationToUseInTestInstance = [ + 'EXTENSIONS' => [ + 'wv_deepltranslate' => [ + 'apiKey' => 'mock_server', + ], + ], + ]; + + protected array $pathsToProvideInTestInstance = [ + 'typo3conf/ext/deepltranslate_core/Tests/Functional/Regression/Fixtures/Files' => 'fileadmin', + ]; + + protected function setUp(): void + { + $this->coreExtensionsToLoad[] = 'typo3/cms-fluid-styled-content'; + $this->testExtensionsToLoad[] = __DIR__ . '/../Fixtures/Extensions/testing_framework_backenduserhandler_replacement'; + parent::setUp(); + $this->importCSVDataSet(__DIR__ . '/Fixtures/PreviewTranslationInformation.csv'); + $this->writeSiteConfiguration( + 'acme', + $this->buildSiteConfiguration(1, 'https://acme.com/', 'Home', [ + 'deeplAllowedAutoTranslate' => true, + 'deeplAllowedReTranslate' => true, + ]), + [ + $this->buildDefaultLanguageConfiguration('EN', 'https://acme.com/'), + $this->buildLanguageConfiguration('DE', 'https://acme.com/de/', ['EN'], 'strict'), + ] + ); + $this->setUpFrontendRootPage( + 1, + [ + 'constants' => [ + 'EXT:fluid_styled_content/Configuration/TypoScript/constants.typoscript', + 'EXT:fluid_styled_content/Configuration/TypoScript/Styling/constants.typoscript', + ], + 'setup' => [ + 'EXT:fluid_styled_content/Configuration/TypoScript/setup.typoscript', + 'EXT:fluid_styled_content/Configuration/TypoScript/Styling/setup.typoscript', + 'EXT:deepltranslate_core/Tests/Functional/Regression/Fixtures/PreviewTranslationInformation.typoscript', + ], + ], + [ + 'title' => 'ACME Root', + ] + ); + $this->setUpBackendUser(1); + $GLOBALS['LANG'] = GeneralUtility::makeInstance(LanguageServiceFactory::class) + ->createFromUserPreferences($GLOBALS['BE_USER']); + } + + /** + * @test + */ + public function previewTranslationInformationIsRenderedForTranslatedPage(): void + { + $styles = []; + $styles[] = 'position: fixed'; + $styles[] = 'top: 65px'; + $styles[] = 'right: 15px'; + $styles[] = 'padding: 8px 18px'; + $styles[] = 'background: #006494'; + $styles[] = 'border: 1px solid #006494'; + $styles[] = 'font-family: sans-serif'; + $styles[] = 'font-size: 14px'; + $styles[] = 'font-weight: bold'; + $styles[] = 'color: #fff'; + $styles[] = 'z-index: 20000'; + $styles[] = 'user-select: none'; + $styles[] = 'pointer-events: none'; + $styles[] = 'text-align: center'; + $styles[] = 'border-radius: 2px'; + $expectedContent = '