From cdc1499a1baa456fbb3b1c20d06ebed98c1c15fe Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Thu, 27 Nov 2025 21:37:59 +0100 Subject: [PATCH 01/39] [TASK] Add TYPO3 14 Support --- .devbox/composer.json | 17 +++++++------- .github/workflows/Acceptance.yml | 1 + .github/workflows/Tests.yml | 1 + CHANGELOG.md | 1 + .../SubProcessExecutionStrategyTest.php | 23 ++++++++++++++----- composer.json | 12 +++++----- 6 files changed, 34 insertions(+), 21 deletions(-) diff --git a/.devbox/composer.json b/.devbox/composer.json index 4d4a2d445..5d8e84097 100644 --- a/.devbox/composer.json +++ b/.devbox/composer.json @@ -17,16 +17,15 @@ "require": { "tnm/crawler-devbox-sitepackage": "^0.0.3", "tomasnorre/crawler": "*@dev", - "typo3/cms-belog": "^13.4" , - "typo3/cms-beuser": "^13.4", - "typo3/cms-felogin": "^13.4", - "typo3/cms-indexed-search": "^13.4", - "typo3/cms-info": "^13.4", - "typo3/cms-tstemplate": "^13.4", - "typo3/minimal": "^13.4", - "typo3/cms-install": "^13.4", + "typo3/cms-belog":"^13.4 || ^14.0", + "typo3/cms-beuser": "^13.4 || ^14.0", + "typo3/cms-felogin": "^13.4 || ^14.0", + "typo3/cms-indexed-search": "^13.4 || ^14.0", + "typo3/cms-info": "^13.4 || ^14.0", + "typo3/cms-tstemplate": "^13.4 || ^14.0", + "typo3/minimal": "^13.4 || ^14.0", + "typo3/cms-install": "^13.4 || ^14.0", "georgringer/news": "^14", - "typo3/cms-reports": "^13.4", "symfony/dependency-injection": "7.3.6" }, "require-dev": { diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index b99ee432f..707864fb4 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -15,6 +15,7 @@ jobs: matrix: typo3: - ^13.4 + - ^14.0 php: - '8.2' - '8.3' diff --git a/.github/workflows/Tests.yml b/.github/workflows/Tests.yml index c194d34d0..15cd1ec76 100644 --- a/.github/workflows/Tests.yml +++ b/.github/workflows/Tests.yml @@ -17,6 +17,7 @@ jobs: matrix: typo3: - '^13.4' + - '^14.0' php: - '8.2' - '8.3' diff --git a/CHANGELOG.md b/CHANGELOG.md index fb51004c2..c932c4fde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Added * PHP 8.5 Support [@tomasnorre](https://github.com/tomasnorre) +* TYPO3 14 Support [@tomasnorre](https://github.com/tomasnorre) ### Changed * Updated symfony-components dependencies to ^7.2 diff --git a/Tests/Unit/CrawlStrategy/SubProcessExecutionStrategyTest.php b/Tests/Unit/CrawlStrategy/SubProcessExecutionStrategyTest.php index 97854dea9..018e18de8 100644 --- a/Tests/Unit/CrawlStrategy/SubProcessExecutionStrategyTest.php +++ b/Tests/Unit/CrawlStrategy/SubProcessExecutionStrategyTest.php @@ -24,6 +24,7 @@ use Prophecy\PhpUnit\ProphecyTrait; use Psr\Log\LoggerInterface; use TYPO3\CMS\Core\Http\Uri; +use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; @@ -56,12 +57,22 @@ public function constructorTest(): void public function fetchUrlContentsInvalidSchema(): void { $logger = $this->prophesize(LoggerInterface::class); - $logger->debug( - 'Scheme does not match for url "/not-an-url"', - [ - 'crawlerId' => '2981d019ade833a37995c1b569ef87b6b5af7287', - ] - )->shouldBeCalledOnce(); + $typo3Version = GeneralUtility::makeInstance(Typo3Version::class); + if ($typo3Version->getMajorVersion() < 14) { + $logger->debug( + 'Scheme does not match for url "/not-an-url"', + [ + 'crawlerId' => '2981d019ade833a37995c1b569ef87b6b5af7287', + ] + )->shouldBeCalledOnce(); + } else { + $logger->debug( + 'Scheme does not match for url "not-an-url"', + [ + 'crawlerId' => '2981d019ade833a37995c1b569ef87b6b5af7287', + ] + )->shouldBeCalledOnce(); + } $crawlerId = sha1('this-is-testing'); $url = new Uri('not-an-url'); diff --git a/composer.json b/composer.json index aef3ca57f..626d930d0 100644 --- a/composer.json +++ b/composer.json @@ -31,12 +31,12 @@ "psr/log": "^1.0 || ^2.0 || ^3.0", "symfony/console": "^7.2", "symfony/service-contracts": "^3.6", - "typo3/cms-backend": "^13.4", - "typo3/cms-core": "^13.4", - "typo3/cms-extbase": "^13.4", - "typo3/cms-frontend": "^13.4", - "typo3/cms-info": "^13.4", - "typo3/cms-seo": "^13.4" + "typo3/cms-backend": "^13.4 || ^14.0", + "typo3/cms-core": "^13.4 || ^14.0", + "typo3/cms-extbase": "^13.4 || ^14.0", + "typo3/cms-frontend": "^13.4 || ^14.0", + "typo3/cms-info": "^13.4 || ^14.0", + "typo3/cms-seo": "^13.4 || ^14.0" }, "require-dev": { "infection/infection": "^0.29.9", From 94e9ae9f111f0371ac35d4b83b35d519c9384f8b Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Fri, 28 Nov 2025 08:12:08 +0100 Subject: [PATCH 02/39] [TASK] Downgrade symfony/dependency-injection:7.4.0 to 7.3.6 --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 626d930d0..50790787b 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,8 @@ "typo3/cms-extbase": "^13.4 || ^14.0", "typo3/cms-frontend": "^13.4 || ^14.0", "typo3/cms-info": "^13.4 || ^14.0", - "typo3/cms-seo": "^13.4 || ^14.0" + "typo3/cms-seo": "^13.4 || ^14.0", + "symfony/dependency-injection": "7.3.6" }, "require-dev": { "infection/infection": "^0.29.9", From 873921e2ff5140831d0690afc96d2adb6c732929 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 2 Dec 2025 11:49:27 +0100 Subject: [PATCH 03/39] add conflict for symfony/dependency injection 7.4.0 --- .devbox/composer.json | 6 +++--- composer.json | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.devbox/composer.json b/.devbox/composer.json index 5d8e84097..799fe803c 100644 --- a/.devbox/composer.json +++ b/.devbox/composer.json @@ -25,14 +25,14 @@ "typo3/cms-tstemplate": "^13.4 || ^14.0", "typo3/minimal": "^13.4 || ^14.0", "typo3/cms-install": "^13.4 || ^14.0", - "georgringer/news": "^14", - "symfony/dependency-injection": "7.3.6" + "georgringer/news": "^14" }, "require-dev": { "roave/security-advisories": "dev-latest" }, "conflict": { - "tomasnorre/crawler": "<12.0.0" + "tomasnorre/crawler": "<12.0.0", + "symfony/dependency-injection": "7.4.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/composer.json b/composer.json index 50790787b..b092b0b7e 100644 --- a/composer.json +++ b/composer.json @@ -107,6 +107,9 @@ "web-dir": ".Build/Web" } }, + "conflict": { + "symfony/dependency-injection": "7.4.0" + }, "scripts": { "post-autoload-dump": [ "mkdir -p .Build/Web/typo3conf/ext/", From 09440456e33ab605e8ccb4ce8572a3b7ac5a6833 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 2 Dec 2025 11:54:19 +0100 Subject: [PATCH 04/39] composer normalize --- .devbox/composer.json | 16 ++++++++-------- composer.json | 25 ++++++++++++------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/.devbox/composer.json b/.devbox/composer.json index 799fe803c..a0435f9c6 100644 --- a/.devbox/composer.json +++ b/.devbox/composer.json @@ -15,31 +15,31 @@ "issues": "https://github.com/tomasnorre/crawler/issues" }, "require": { + "georgringer/news": "^14", "tnm/crawler-devbox-sitepackage": "^0.0.3", "tomasnorre/crawler": "*@dev", - "typo3/cms-belog":"^13.4 || ^14.0", + "typo3/cms-belog": "^13.4 || ^14.0", "typo3/cms-beuser": "^13.4 || ^14.0", "typo3/cms-felogin": "^13.4 || ^14.0", "typo3/cms-indexed-search": "^13.4 || ^14.0", "typo3/cms-info": "^13.4 || ^14.0", - "typo3/cms-tstemplate": "^13.4 || ^14.0", - "typo3/minimal": "^13.4 || ^14.0", "typo3/cms-install": "^13.4 || ^14.0", - "georgringer/news": "^14" + "typo3/cms-tstemplate": "^13.4 || ^14.0", + "typo3/minimal": "^13.4 || ^14.0" }, "require-dev": { "roave/security-advisories": "dev-latest" }, "conflict": { - "tomasnorre/crawler": "<12.0.0", - "symfony/dependency-injection": "7.4.0" + "symfony/dependency-injection": "7.4.0", + "tomasnorre/crawler": "<12.0.0" }, "minimum-stability": "dev", "prefer-stable": true, "config": { "allow-plugins": { - "typo3/cms-composer-installers": true, - "typo3/class-alias-loader": true + "typo3/class-alias-loader": true, + "typo3/cms-composer-installers": true }, "bin-dir": "bin", "vendor-dir": "vendor" diff --git a/composer.json b/composer.json index b092b0b7e..16a2af317 100644 --- a/composer.json +++ b/composer.json @@ -12,10 +12,10 @@ ], "homepage": "https://github.com/tomasnorre/crawler", "support": { - "docs": "https://docs.typo3.org/p/tomasnorre/crawler/main/en-us/", "issues": "https://github.com/tomasnorre/crawler/issues", + "chat": "https://typo3.slack.com/archives/C087NGBKM", "source": "https://github.com/tomasnorre/crawler/", - "chat": "https://typo3.slack.com/archives/C087NGBKM" + "docs": "https://docs.typo3.org/p/tomasnorre/crawler/main/en-us/" }, "require": { "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", @@ -36,8 +36,7 @@ "typo3/cms-extbase": "^13.4 || ^14.0", "typo3/cms-frontend": "^13.4 || ^14.0", "typo3/cms-info": "^13.4 || ^14.0", - "typo3/cms-seo": "^13.4 || ^14.0", - "symfony/dependency-injection": "7.3.6" + "typo3/cms-seo": "^13.4 || ^14.0" }, "require-dev": { "infection/infection": "^0.29.9", @@ -63,6 +62,9 @@ "aoepeople/crawler": "self.version", "typo3-ter/crawler": "self.version" }, + "conflict": { + "symfony/dependency-injection": "7.4.0" + }, "suggest": { "typo3/cms-seo": "Enables the posibility to priorities your Crawler Queue + You have seo features in the CMS it self." }, @@ -84,9 +86,9 @@ "composer/package-versions-deprecated": true, "infection/extension-installer": true, "phpstan/extension-installer": true, + "sbuerk/typo3-cmscomposerinstallers-testingframework-bridge": true, "typo3/class-alias-loader": true, - "typo3/cms-composer-installers": true, - "sbuerk/typo3-cmscomposerinstallers-testingframework-bridge": true + "typo3/cms-composer-installers": true }, "bin-dir": ".Build/bin", "preferred-install": { @@ -107,9 +109,6 @@ "web-dir": ".Build/Web" } }, - "conflict": { - "symfony/dependency-injection": "7.4.0" - }, "scripts": { "post-autoload-dump": [ "mkdir -p .Build/Web/typo3conf/ext/", @@ -128,6 +127,10 @@ "extension-create-libs": [ "@composer install -d Resources/Private/Php/Libraries" ], + "phpstan-baseline": [ + "[ -e .Build/bin/phpstan ] || composer update", + ".Build/bin/phpstan analyse --generate-baseline" + ], "prepare-release": [ "@extension-create-libs", "rm -rf .devbox", @@ -143,10 +146,6 @@ "rm -f psalm-baseline.xml", "rm -f crowdin.yml" ], - "phpstan-baseline": [ - "[ -e .Build/bin/phpstan ] || composer update", - ".Build/bin/phpstan analyse --generate-baseline" - ], "psalm": [ "[ -e .Build/bin/psalm ] || composer update", ".Build/bin/psalm --no-cache" From 5c00500f955b5241316340c894dcf670de200094 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 3 Dec 2025 15:01:51 +0100 Subject: [PATCH 05/39] update tests --- Tests/Functional/BackendRequestTestTrait.php | 8 ++++ .../Service/BackendModuleLinkServiceTest.php | 45 ++++++++++++++++--- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/Tests/Functional/BackendRequestTestTrait.php b/Tests/Functional/BackendRequestTestTrait.php index f62194540..c176f8bb1 100644 --- a/Tests/Functional/BackendRequestTestTrait.php +++ b/Tests/Functional/BackendRequestTestTrait.php @@ -23,7 +23,9 @@ use TYPO3\CMS\Backend\Routing\Route; use TYPO3\CMS\Backend\Routing\Router; use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder; +use TYPO3\CMS\Core\Http\NormalizedParams; use TYPO3\CMS\Core\Http\ServerRequest; +use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\CMS\Core\Utility\GeneralUtility; trait BackendRequestTestTrait @@ -45,6 +47,12 @@ protected function setupBackendRequest(): void 'route' => '/web_info', ]); $request = $request->withAttribute('route', $route); + + $typo3version = new Typo3Version(); + if ($typo3version->getMajorVersion() >=14) { + $request = $request->withAttribute('normalizedParams', new NormalizedParams([], [], '', '')); + } + $request = $request->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_BE); $GLOBALS['TYPO3_REQUEST'] = $request; } diff --git a/Tests/Functional/Service/BackendModuleLinkServiceTest.php b/Tests/Functional/Service/BackendModuleLinkServiceTest.php index b39362db9..a7b2395a5 100644 --- a/Tests/Functional/Service/BackendModuleLinkServiceTest.php +++ b/Tests/Functional/Service/BackendModuleLinkServiceTest.php @@ -26,7 +26,9 @@ use TYPO3\CMS\Backend\Template\ModuleTemplate; use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder; +use TYPO3\CMS\Core\Http\NormalizedParams; use TYPO3\CMS\Core\Http\ServerRequest; +use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\CMS\Core\Routing\Route; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; @@ -40,6 +42,8 @@ class BackendModuleLinkServiceTest extends FunctionalTestCase private BackendModuleLinkService $subject; private ModuleTemplate $moduleTemplate; + private Typo3Version $typo3Version; + protected function setUp(): void { parent::setUp(); @@ -47,6 +51,7 @@ protected function setUp(): void $this->setupLanguageService(); $this->subject = GeneralUtility::makeInstance(BackendModuleLinkService::class); + $this->typo3Version = new Typo3Version(); $request = (new ServerRequest('https://example.com/typo3/')) ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_BE) @@ -54,6 +59,10 @@ protected function setUp(): void 'packageName' => 'tomasnorre/crawler', ])); + if ($this->typo3Version->getMajorVersion() >= 14) { + $request = $request->withAttribute('normalizedParams', new NormalizedParams([], [], '', '')); + } + $this->moduleTemplate = (GeneralUtility::makeInstance(ModuleTemplateFactory::class))->create($request); } @@ -64,7 +73,11 @@ public function getRefreshLinkReturnLink(): void self::assertIsString($link); self::assertStringContainsString('Refresh', $link); - self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + if ($this->typo3Version->getMajorVersion() < 14) { + self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + } else { + self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); + } self::assertStringContainsString('SET%5B%27crawleraction%27%5D=crawleraction&id=1', $link); } @@ -83,7 +96,11 @@ public function getAddLinkReturnLink(): void self::assertIsString($link); self::assertStringContainsString('Add process', $link); - self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + if ($this->typo3Version->getMajorVersion() < 14) { + self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + } else { + self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); + } self::assertStringContainsString('action=addProcess', $link); } @@ -100,7 +117,11 @@ public function getModeLinkReturnsDatailLink(): void self::assertIsString($link); self::assertStringContainsString('Show only running processes', $link); - self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + if ($this->typo3Version->getMajorVersion() < 14) { + self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + } else { + self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); + } self::assertStringContainsString('processListMode=simple', $link); } @@ -111,7 +132,11 @@ public function getModeLinkReturnsSimpleLink(): void self::assertIsString($link); self::assertStringContainsString('Show finished and terminated processes', $link); - self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + if ($this->typo3Version->getMajorVersion() < 14) { + self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + } else { + self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); + } self::assertStringContainsString('processListMode=detail', $link); } @@ -122,7 +147,11 @@ public function getEnableDisableLinkReturnsEnableLink(): void self::assertIsString($link); self::assertStringContainsString('Stop all processes and disable crawling', $link); - self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + if ($this->typo3Version->getMajorVersion() < 14) { + self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + } else { + self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); + } self::assertStringContainsString('action=stopCrawling', $link); } @@ -133,7 +162,11 @@ public function getEnableDisableLinkReturnsDisableLink(): void self::assertIsString($link); self::assertStringContainsString('Enable crawling', $link); - self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + if ($this->typo3Version->getMajorVersion() < 14) { + self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); + } else { + self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); + } self::assertStringContainsString('action=resumeCrawling', $link); } } From 2d8b1d736e10492a498ff598685f1da5ebc8cb16 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 3 Dec 2025 15:44:30 +0100 Subject: [PATCH 06/39] update tests --- Classes/Service/ConfigurationService.php | 2 +- Tests/Functional/BackendRequestTestTrait.php | 3 +-- .../Middleware/CrawlerInitializationTest.php | 21 +++++++++++++------ .../Service/BackendModuleLinkServiceTest.php | 17 +++++++-------- phpstan-baseline.neon | 18 ++++++++++++++++ 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/Classes/Service/ConfigurationService.php b/Classes/Service/ConfigurationService.php index e584d6106..b3732e714 100644 --- a/Classes/Service/ConfigurationService.php +++ b/Classes/Service/ConfigurationService.php @@ -387,7 +387,7 @@ private function addValuesInRange(array $reg, array $paramArray, int|string $par private function expandPidList(array $treeCache, int $pid, int $depth, PageTreeView $tree, array $pidList): array { if (empty($treeCache[$pid][$depth])) { - $tree->reset(); + //$tree->reset(); $tree->getTree($pid, $depth); $treeCache[$pid][$depth] = $tree->tree; } diff --git a/Tests/Functional/BackendRequestTestTrait.php b/Tests/Functional/BackendRequestTestTrait.php index c176f8bb1..b1024e202 100644 --- a/Tests/Functional/BackendRequestTestTrait.php +++ b/Tests/Functional/BackendRequestTestTrait.php @@ -48,8 +48,7 @@ protected function setupBackendRequest(): void ]); $request = $request->withAttribute('route', $route); - $typo3version = new Typo3Version(); - if ($typo3version->getMajorVersion() >=14) { + if ((new Typo3Version())->getMajorVersion() >= 14) { $request = $request->withAttribute('normalizedParams', new NormalizedParams([], [], '', '')); } diff --git a/Tests/Functional/Middleware/CrawlerInitializationTest.php b/Tests/Functional/Middleware/CrawlerInitializationTest.php index ee65e447e..b9777c833 100644 --- a/Tests/Functional/Middleware/CrawlerInitializationTest.php +++ b/Tests/Functional/Middleware/CrawlerInitializationTest.php @@ -20,16 +20,20 @@ */ use AOE\Crawler\Middleware\CrawlerInitialization; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use Prophecy\PhpUnit\ProphecyTrait; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use TYPO3\CMS\Core\Http\Response; +use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Frontend\Cache\CacheInstruction; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; -#[\PHPUnit\Framework\Attributes\CoversClass(\AOE\Crawler\Middleware\CrawlerInitialization::class)] +#[CoversClass(CrawlerInitialization::class)] class CrawlerInitializationTest extends FunctionalTestCase { use ProphecyTrait; @@ -40,15 +44,20 @@ protected function setUp(): void { parent::setUp(); $this->subject = GeneralUtility::makeInstance(CrawlerInitialization::class); - $tsfe = $this->prophesize(TypoScriptFrontendController::class); - $GLOBALS['TSFE'] = $tsfe->reveal(); - $GLOBALS['TSFE']->id = random_int(0, 10000); + if ((new Typo3Version())->getMajorVersion() < 14) { + $tsfe = $this->prophesize(TypoScriptFrontendController::class); + $GLOBALS['TSFE'] = $tsfe->reveal(); + $GLOBALS['TSFE']->id = random_int(0, 10000); + } } - #[\PHPUnit\Framework\Attributes\DataProvider('processSetsTSFEApplicationDataDataProvider')] - #[\PHPUnit\Framework\Attributes\Test] + #[DataProvider('processSetsTSFEApplicationDataDataProvider')] + #[Test] public function processSetsTSFEApplicationData(string $feGroups, array $expectedGroups): void { + if ((new Typo3Version())->getMajorVersion() === 14) { + self::markTestSkipped('Needs to updated with issue #1137'); + } self::assertEmpty($GLOBALS['TSFE']->applicationData); $queueParameters = [ diff --git a/Tests/Functional/Service/BackendModuleLinkServiceTest.php b/Tests/Functional/Service/BackendModuleLinkServiceTest.php index a7b2395a5..7002967a1 100644 --- a/Tests/Functional/Service/BackendModuleLinkServiceTest.php +++ b/Tests/Functional/Service/BackendModuleLinkServiceTest.php @@ -42,8 +42,6 @@ class BackendModuleLinkServiceTest extends FunctionalTestCase private BackendModuleLinkService $subject; private ModuleTemplate $moduleTemplate; - private Typo3Version $typo3Version; - protected function setUp(): void { parent::setUp(); @@ -51,7 +49,6 @@ protected function setUp(): void $this->setupLanguageService(); $this->subject = GeneralUtility::makeInstance(BackendModuleLinkService::class); - $this->typo3Version = new Typo3Version(); $request = (new ServerRequest('https://example.com/typo3/')) ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_BE) @@ -59,7 +56,7 @@ protected function setUp(): void 'packageName' => 'tomasnorre/crawler', ])); - if ($this->typo3Version->getMajorVersion() >= 14) { + if ((new Typo3Version())->getMajorVersion() >= 14) { $request = $request->withAttribute('normalizedParams', new NormalizedParams([], [], '', '')); } @@ -73,7 +70,7 @@ public function getRefreshLinkReturnLink(): void self::assertIsString($link); self::assertStringContainsString('Refresh', $link); - if ($this->typo3Version->getMajorVersion() < 14) { + if ((new Typo3Version())->getMajorVersion() < 14) { self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); } else { self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); @@ -96,7 +93,7 @@ public function getAddLinkReturnLink(): void self::assertIsString($link); self::assertStringContainsString('Add process', $link); - if ($this->typo3Version->getMajorVersion() < 14) { + if ((new Typo3Version())->getMajorVersion() < 14) { self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); } else { self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); @@ -117,7 +114,7 @@ public function getModeLinkReturnsDatailLink(): void self::assertIsString($link); self::assertStringContainsString('Show only running processes', $link); - if ($this->typo3Version->getMajorVersion() < 14) { + if ((new Typo3Version())->getMajorVersion() < 14) { self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); } else { self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); @@ -132,7 +129,7 @@ public function getModeLinkReturnsSimpleLink(): void self::assertIsString($link); self::assertStringContainsString('Show finished and terminated processes', $link); - if ($this->typo3Version->getMajorVersion() < 14) { + if ((new Typo3Version())->getMajorVersion() < 14) { self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); } else { self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); @@ -147,7 +144,7 @@ public function getEnableDisableLinkReturnsEnableLink(): void self::assertIsString($link); self::assertStringContainsString('Stop all processes and disable crawling', $link); - if ($this->typo3Version->getMajorVersion() < 14) { + if ((new Typo3Version())->getMajorVersion() < 14) { self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); } else { self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); @@ -162,7 +159,7 @@ public function getEnableDisableLinkReturnsDisableLink(): void self::assertIsString($link); self::assertStringContainsString('Enable crawling', $link); - if ($this->typo3Version->getMajorVersion() < 14) { + if ((new Typo3Version())->getMajorVersion() < 14) { self::assertStringContainsString('href="/typo3/module/page/crawler/process', $link); } else { self::assertStringContainsString('href="typo3/module/page/crawler/process', $link); diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index b4225b713..593a77646 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,5 +1,14 @@ parameters: ignoreErrors: + - + message: ''' + #^Call to deprecated method setMetaInformation\(\) of class TYPO3\\CMS\\Backend\\Template\\Components\\DocHeaderComponent\: + since v14, will be removed in v15\. Use setPageBreadcrumb\(\) instead\.$# + ''' + identifier: method.deprecated + count: 1 + path: Classes/Controller/Backend/AbstractBackendModuleController.php + - message: '#^Cannot access offset ''_flush'' on array\|object\.$#' identifier: offsetAccess.nonOffsetAccessible @@ -66,6 +75,15 @@ parameters: count: 2 path: Classes/Domain/Model/ProcessCollection.php + - + message: ''' + #^Call to deprecated method makeLinkButton\(\) of class TYPO3\\CMS\\Backend\\Template\\Components\\ButtonBar\: + since v14, will be removed in v15\. Inject ComponentFactory and use ComponentFactory\:\:createLinkButton\(\) instead\.$# + ''' + identifier: method.deprecated + count: 1 + path: Classes/Service/BackendModuleLinkService.php + - message: '#^Cannot access offset ''alturl'' on array\|bool\.$#' identifier: offsetAccess.nonOffsetAccessible From c990b88b6c58b2520d6598388395e36138e65f14 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Mon, 19 Jan 2026 12:29:07 +0100 Subject: [PATCH 07/39] feat: update sitepage to 0.0.5 --- .devbox/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devbox/composer.json b/.devbox/composer.json index a0435f9c6..636b65950 100644 --- a/.devbox/composer.json +++ b/.devbox/composer.json @@ -16,7 +16,7 @@ }, "require": { "georgringer/news": "^14", - "tnm/crawler-devbox-sitepackage": "^0.0.3", + "tnm/crawler-devbox-sitepackage": "^0.0.5", "tomasnorre/crawler": "*@dev", "typo3/cms-belog": "^13.4 || ^14.0", "typo3/cms-beuser": "^13.4 || ^14.0", From 388fc4a3c9692658a68bef4ee5acfe14f9a05313 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Mon, 19 Jan 2026 12:41:00 +0100 Subject: [PATCH 08/39] fix: update phpstan baseline --- phpstan-baseline.neon | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 177e51392..2c1a7d90e 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -75,6 +75,15 @@ parameters: count: 2 path: Classes/Domain/Model/ProcessCollection.php + - + message: ''' + #^Call to deprecated method makeLinkButton\(\) of class TYPO3\\CMS\\Backend\\Template\\Components\\ButtonBar\: + since v14, will be removed in v15\. Inject ComponentFactory and use ComponentFactory\:\:createLinkButton\(\) instead\.$# + ''' + identifier: method.deprecated + count: 1 + path: Classes/Service/BackendModuleLinkService.php + - message: '#^Method AOE\\Crawler\\Service\\BackendModuleLogService\:\:addRows\(\) should return non\-empty\-list\, colSpan\: int, title\: string, noEntries\?\: string, trClass\?\: string, qid\?\: array\{link\: TYPO3\\CMS\\Core\\Http\\Uri, link\-text\: string\}, refresh\?\: array\{link\: TYPO3\\CMS\\Core\\Http\\Uri, link\-text\: TYPO3\\CMS\\Core\\Imaging\\Icon, warning\: string\|TYPO3\\CMS\\Core\\Imaging\\Icon\}, columns\?\: array\{url\: mixed, scheduled\: string, exec_time\: string, result_log\: string, result_status\: string, feUserGroupList\: string, procInstructions\: string, set_id\: string, \.\.\.\}\}\> but returns array\{non\-empty\-list\, array\}\.$#' identifier: return.type From a24dec4e73cb656775bc28f6c24081421285f12a Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Mon, 19 Jan 2026 17:11:02 +0100 Subject: [PATCH 09/39] feat: add playwright tags --- .github/workflows/Acceptance.yml | 11 ++++++++++- .../Tests/backend_crawler_configuration.spec.js | 2 +- Tests/Acceptance/Tests/backend_module_basic.spec.js | 8 ++++---- Tests/Acceptance/Tests/backend_module_log.spec.js | 2 +- Tests/Acceptance/Tests/backend_module_process.spec.js | 8 ++++---- .../Tests/backend_module_start_crawling.spec.js | 6 +++--- Tests/Acceptance/Tests/frontend.spec.js | 6 +++--- 7 files changed, 26 insertions(+), 17 deletions(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index c36b08a0b..547671e07 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -35,6 +35,15 @@ jobs: shell: bash run: echo "BRANCH_NAME=$(echo ${GITHUB_HEAD_REF})" >> $GITHUB_ENV + - name: Set Playwright tag + shell: bash + run: | + if [[ "${{ matrix.typo3 }}" == "^13.4" ]]; then + echo "PW_GREP=@v13" >> $GITHUB_ENV + elif [[ "${{ matrix.typo3 }}" == "^14.0" ]]; then + echo "PW_GREP=@v14" >> $GITHUB_ENV + fi + - uses: actions/checkout@v6 - name: Patch composer.json for forked PR if: > @@ -75,7 +84,7 @@ jobs: - name: Install Playwright Browsers run: cd Tests/Acceptance && npx playwright install --with-deps - name: Run Playwright tests - run: cd Tests/Acceptance && npx playwright test + run: cd Tests/Acceptance && npx playwright test --grep "$PW_GREP" - uses: actions/upload-artifact@v6 if: ${{ !cancelled() }} with: diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index d410bd4fb..05c33a78d 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -1,7 +1,7 @@ import { test, expect } from '@playwright/test'; import * as helpers from './helpers'; -test('test', async ({ page }) => { +test('Enable to create and save crawler configuration', { tag: '@v13' }, async ({ page}) => { await helpers.loginBackend(page) await page.getByTitle('List', { exact: true }).click(); await page.locator('div.node:nth-child(2)').click(); diff --git a/Tests/Acceptance/Tests/backend_module_basic.spec.js b/Tests/Acceptance/Tests/backend_module_basic.spec.js index 7025108d6..f78e4012e 100644 --- a/Tests/Acceptance/Tests/backend_module_basic.spec.js +++ b/Tests/Acceptance/Tests/backend_module_basic.spec.js @@ -3,25 +3,25 @@ const {test, expect} = require('@playwright/test'); import * as helpers from './helpers'; -test('Can see crawler backend module', async ({page}) => { +test('Can see crawler backend module', { tag: ['@v13'] }, async ({page}) => { await helpers.loginBackend(page) await helpers.openCrawlerModule(page); await expect(page).toHaveURL('/typo3/module/page/crawler'); }); -test('Can select and see crawler module start crawling', async ({page}) => { +test('Can select and see crawler module start crawling', { tag: ['@v13','@v14'] }, async ({page}) => { await helpers.loginBackend(page) await helpers.openCrawlerModuleStartCrawling(page); await expect(page).toHaveURL('/typo3/module/page/crawler/start?id=1'); }); -test('Can select and see crawler module log', async ({page}) => { +test('Can select and see crawler module log', { tag: ['@v13','@v14'] }, async ({page}) => { await helpers.loginBackend(page) await helpers.openCrawlerModuleCrawlerLog(page); await expect(page).toHaveURL('/typo3/module/page/crawler/log?id=1'); }) -test('Can select and see crawler module process', async ({page}) => { +test('Can select and see crawler module process', { tag: ['@v13','@v14'] }, async ({page}) => { await helpers.loginBackend(page) await helpers.openCrawlerModuleCrawlerProcesses(page) await expect(page).toHaveURL('/typo3/module/page/crawler/process?id=1'); diff --git a/Tests/Acceptance/Tests/backend_module_log.spec.js b/Tests/Acceptance/Tests/backend_module_log.spec.js index 4d38ffc31..c33e7348b 100644 --- a/Tests/Acceptance/Tests/backend_module_log.spec.js +++ b/Tests/Acceptance/Tests/backend_module_log.spec.js @@ -1,7 +1,7 @@ import {test, expect} from '@playwright/test'; import * as helpers from './helpers'; -test('Can crawl manually in log module, and keep selected log depth', async ({page}) => { +test('Can crawl manually in log module, and keep selected log depth', { tag: ['@v13'] },async ({page}) => { await helpers.loginBackend(page) await helpers.addQueueEntries(page, 'default', '99'); await helpers.openCrawlerModuleCrawlerLog(page) diff --git a/Tests/Acceptance/Tests/backend_module_process.spec.js b/Tests/Acceptance/Tests/backend_module_process.spec.js index b26ce3890..8120c3dee 100644 --- a/Tests/Acceptance/Tests/backend_module_process.spec.js +++ b/Tests/Acceptance/Tests/backend_module_process.spec.js @@ -11,7 +11,7 @@ async function addQueueEntries(page, config, depth = '0') { await expect(page.locator('#nprogress')).toHaveCount(0); } -test('Can Flush all processes', async ({page}) => { +test('Can Flush all processes', { tag: ['@v13'] },async ({page}) => { await helpers.loginBackend(page) await addQueueEntries(page, 'default', '99'); await helpers.openCrawlerModuleCrawlerProcesses(page) @@ -22,7 +22,7 @@ test('Can Flush all processes', async ({page}) => { await expect(page.locator('iframe[name="list_frame"]').contentFrame().locator('#processes tbody tr')).toHaveCount(0) }); -test('Can disable and enable crawler', async ({page}) => { +test('Can disable and enable crawler', { tag: ['@v13','@v14'] },async ({page}) => { await helpers.loginBackend(page) await helpers.openCrawlerModuleCrawlerProcesses(page); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', {name: 'Stop all processes and'}).click(); @@ -31,7 +31,7 @@ test('Can disable and enable crawler', async ({page}) => { await expect(page.locator('iframe[name="list_frame"]').contentFrame().locator('body')).toContainText('Stop all processes and disable crawling'); }); -test('Can add process', async ({page}) => { +test('Can add process', { tag: ['@v13'] },async ({page}) => { await helpers.loginBackend(page) await addQueueEntries(page, 'default') await expect(page.locator('iframe[name="list_frame"]').contentFrame().getByText('URLs submitted')).toContainText('1 URLs submitted'); @@ -41,7 +41,7 @@ test('Can add process', async ({page}) => { await expect(page.locator('iframe[name="list_frame"]').contentFrame().getByText('New process has been started')).toContainText('New process has been started'); }); -test('Process successful', async ({page}) => { +test('Process successful', { tag: ['@v13'] },async ({page}) => { await helpers.loginBackend(page) await addQueueEntries(page, 'default') await expect(page.locator('iframe[name="list_frame"]').contentFrame().getByText('URLs submitted')).toContainText('1 URLs submitted'); diff --git a/Tests/Acceptance/Tests/backend_module_start_crawling.spec.js b/Tests/Acceptance/Tests/backend_module_start_crawling.spec.js index 5ca3bc10b..b1bf558ee 100644 --- a/Tests/Acceptance/Tests/backend_module_start_crawling.spec.js +++ b/Tests/Acceptance/Tests/backend_module_start_crawling.spec.js @@ -1,7 +1,7 @@ import { test, expect } from '@playwright/test'; import * as helpers from './helpers'; -test('Update URL button', async ({ page }) => { +test('Update URL button', { tag: ['@v13'] },async ({ page }) => { await helpers.loginBackend(page) await helpers.openCrawlerModuleStartCrawling(page) await page.locator('div.node:nth-child(2)').click(); @@ -12,7 +12,7 @@ test('Update URL button', async ({ page }) => { await expect(page.locator('iframe[name="list_frame"]').contentFrame().getByText('Count')).toContainText('Count: 1'); }); -test('CrawlerConfigurationWithExcludePageSixPlusThree', async ({ page }) => { +test('CrawlerConfigurationWithExcludePageSixPlusThree', { tag: ['@v13'] }, async ({ page }) => { await helpers.loginBackend(page) await helpers.openCrawlerModuleStartCrawling(page) await page.locator('div.node:nth-child(2)').click(); @@ -24,7 +24,7 @@ test('CrawlerConfigurationWithExcludePageSixPlusThree', async ({ page }) => { await expect(page.locator('iframe[name="list_frame"]').contentFrame().getByRole('document')).not.toContainText('TypeError'); }); -test('UpdateUrlButtonSetDepth', async ({ page }) => { +test('UpdateUrlButtonSetDepth', { tag: ['@v13'] }, async ({ page }) => { await helpers.loginBackend(page) await helpers.openCrawlerModuleStartCrawling(page) await page.locator('div.node:nth-child(2)').click(); diff --git a/Tests/Acceptance/Tests/frontend.spec.js b/Tests/Acceptance/Tests/frontend.spec.js index 801109449..4e9e37e1d 100644 --- a/Tests/Acceptance/Tests/frontend.spec.js +++ b/Tests/Acceptance/Tests/frontend.spec.js @@ -1,18 +1,18 @@ // @ts-check const {test, expect} = require('@playwright/test'); -test('Can see homepage', async ({page}) => { +test('Can see homepage',{ tag: ['@v13','@v14'] }, async ({page}) => { await page.goto('/'); await expect(page.getByRole('list').first()).toContainText('Search'); await expect(page.getByRole('list').first()).toContainText('Login'); }); -test('Can see news page', async ({page}) => { +test('Can see news page',{ tag: ['@v13','@v14'] }, async ({page}) => { await page.goto('/news'); await expect(page.getByRole('document')).toContainText('No news available.'); }); -test.skip('Can see search page and search for Tomasnorre', async ({page}) => { +test.skip('Can see search page and search for Tomasnorre', { tag: ['@v13','@v14'] },async ({page}) => { await page.goto('/search'); await expect(page.getByRole('document')).toContainText('Search'); From ff68231f536c2867eb0e023d3bea7a5eb68da941 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 12:12:02 +0100 Subject: [PATCH 10/39] fix: test for crawler configuration --- .../Tests/backend_crawler_configuration.spec.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index 05c33a78d..99ee8ff03 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -1,7 +1,7 @@ import { test, expect } from '@playwright/test'; import * as helpers from './helpers'; -test('Enable to create and save crawler configuration', { tag: '@v13' }, async ({ page}) => { +test('Able to create and save crawler configuration v13', { tag: '@v13' }, async ({ page}) => { await helpers.loginBackend(page) await page.getByTitle('List', { exact: true }).click(); await page.locator('div.node:nth-child(2)').click(); @@ -11,3 +11,14 @@ test('Enable to create and save crawler configuration', { tag: '@v13' }, async ( await page.locator('iframe[name="list_frame"]').contentFrame().getByLabel('Name').fill('Test Configuration'); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'Save' }).click(); }); + +test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page}) => { + await helpers.loginBackend(page) + await page.getByTitle('Records', { exact: true }).click(); + await page.locator('div.node:nth-child(2)').click(); + await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'New Crawler Configuration' }).click(); + await expect(page.locator('iframe[name="list_frame"]').contentFrame().locator('h1')).toContainText('Create new Crawler Configuration on page "Welcome"'); + //await page.locator('iframe[name="list_frame"]').contentFrame().getByLabel('Name').click(); + await page.locator('iframe[name="list_frame"]').contentFrame().getByLabel('Name').fill('Test Configuration'); + await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'Save' }).click(); +}); From c34c8307cd3873c12301a962a986e05d6c902fd1 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 12:26:45 +0100 Subject: [PATCH 11/39] fix: adjust Module configuration to v14 --- Configuration/Backend/Modules.php | 4 ++-- Tests/Acceptance/Tests/backend_module_basic.spec.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Configuration/Backend/Modules.php b/Configuration/Backend/Modules.php index 43b189ca2..6162dc352 100644 --- a/Configuration/Backend/Modules.php +++ b/Configuration/Backend/Modules.php @@ -23,9 +23,9 @@ return [ 'web_site_crawler' => [ - 'parent' => 'web', + 'parent' => 'content', 'position' => [ - 'after' => 'web_info', + 'after' => 'content_status', ], 'access' => 'user', 'workspaces' => 'live', diff --git a/Tests/Acceptance/Tests/backend_module_basic.spec.js b/Tests/Acceptance/Tests/backend_module_basic.spec.js index f78e4012e..e5c2108f1 100644 --- a/Tests/Acceptance/Tests/backend_module_basic.spec.js +++ b/Tests/Acceptance/Tests/backend_module_basic.spec.js @@ -3,7 +3,7 @@ const {test, expect} = require('@playwright/test'); import * as helpers from './helpers'; -test('Can see crawler backend module', { tag: ['@v13'] }, async ({page}) => { +test('Can see crawler backend module', { tag: ['@v13', '@v14'] }, async ({page}) => { await helpers.loginBackend(page) await helpers.openCrawlerModule(page); await expect(page).toHaveURL('/typo3/module/page/crawler'); From 731eaac471b931bfaaeae69a7cb8f9eb7a0cc019 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 12:31:14 +0100 Subject: [PATCH 12/39] update rector suggestions --- Classes/Command/BuildQueueCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Command/BuildQueueCommand.php b/Classes/Command/BuildQueueCommand.php index d05656ebc..4a2e061be 100644 --- a/Classes/Command/BuildQueueCommand.php +++ b/Classes/Command/BuildQueueCommand.php @@ -234,7 +234,7 @@ private function outputModeExec(OutputInterface $output, array $queueRows): void $result = $this->crawlerController->readUrlFromArray($queueRec); $resultContent = $result['content'] ?? ''; - $requestResult = json_decode($resultContent, true); + $requestResult = json_decode((string) $resultContent, true); $progressBar->clear(); if (is_array($requestResult)) { From 33accf0bb28f5a5fff97f625bee6476fb65f3381 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 12:43:41 +0100 Subject: [PATCH 13/39] remove module icons --- Configuration/Backend/Modules.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/Configuration/Backend/Modules.php b/Configuration/Backend/Modules.php index 6162dc352..37ae09ced 100644 --- a/Configuration/Backend/Modules.php +++ b/Configuration/Backend/Modules.php @@ -43,7 +43,6 @@ 'parent' => 'web_site_crawler', 'access' => 'user', 'path' => '/module/page/crawler/start', - 'iconIdentifier' => 'crawler-start', 'labels' => [ 'title' => 'Start', ], @@ -57,7 +56,6 @@ 'parent' => 'web_site_crawler', 'access' => 'user', 'path' => '/module/page/crawler/process', - 'iconIdentifier' => 'crawler-process', 'labels' => [ 'title' => 'Process', ], @@ -71,7 +69,6 @@ 'parent' => 'web_site_crawler', 'access' => 'user', 'path' => '/module/page/crawler/log', - 'iconIdentifier' => 'crawler-log', 'labels' => [ 'title' => 'Log', ], From 7058db11d7b52350d58545e258cb4608cb5fc224 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 17:38:47 +0100 Subject: [PATCH 14/39] Add if to Modules configuration --- Configuration/Backend/Modules.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Configuration/Backend/Modules.php b/Configuration/Backend/Modules.php index 37ae09ced..373af64b0 100644 --- a/Configuration/Backend/Modules.php +++ b/Configuration/Backend/Modules.php @@ -21,12 +21,18 @@ use AOE\Crawler\Controller\Backend\BackendModuleCrawlerProcessController; use AOE\Crawler\Controller\Backend\BackendModuleStartCrawlingController; +if ((new \TYPO3\CMS\Core\Information\Typo3Version())->getMajorVersion() === 14) { + $parent = 'content'; + $position = ['after' => 'content_status']; +} else { + $parent = 'web'; + $position = ['after' => 'web_info']; +} + return [ 'web_site_crawler' => [ - 'parent' => 'content', - 'position' => [ - 'after' => 'content_status', - ], + 'parent' => $parent, + 'position' => $position, 'access' => 'user', 'workspaces' => 'live', 'path' => '/module/page/crawler', From dffb7bc8c55db7146246d42c37adce91feb9258e Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 17:41:49 +0100 Subject: [PATCH 15/39] update code style --- Configuration/Backend/Modules.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Configuration/Backend/Modules.php b/Configuration/Backend/Modules.php index 373af64b0..5d7c18588 100644 --- a/Configuration/Backend/Modules.php +++ b/Configuration/Backend/Modules.php @@ -23,10 +23,14 @@ if ((new \TYPO3\CMS\Core\Information\Typo3Version())->getMajorVersion() === 14) { $parent = 'content'; - $position = ['after' => 'content_status']; + $position = [ + 'after' => 'content_status', + ]; } else { $parent = 'web'; - $position = ['after' => 'web_info']; + $position = [ + 'after' => 'web_info', + ]; } return [ From e6b07e5e6e4fc585b94e34dd930ae0e63b4686b2 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 17:43:30 +0100 Subject: [PATCH 16/39] remove cs-fix before psalm --- .github/workflows/StaticAnalysis.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/StaticAnalysis.yaml b/.github/workflows/StaticAnalysis.yaml index e2b06b512..f509991c1 100644 --- a/.github/workflows/StaticAnalysis.yaml +++ b/.github/workflows/StaticAnalysis.yaml @@ -91,6 +91,5 @@ jobs: coverage: none - name: "Install dependencies" uses: ramsey/composer-install@v3 - - run: composer cs-fix - run: .Build/bin/psalm --no-cache --shepherd From 08a0c79d0f3a4d17656d82763b50f45f832e0365 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 18:03:37 +0100 Subject: [PATCH 17/39] update tests --- Tests/Acceptance/Tests/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Acceptance/Tests/helpers.js b/Tests/Acceptance/Tests/helpers.js index b79f1c755..788afb64a 100644 --- a/Tests/Acceptance/Tests/helpers.js +++ b/Tests/Acceptance/Tests/helpers.js @@ -8,7 +8,7 @@ export async function loginBackend(page) { } export async function openCrawlerModule(page) { - await page.getByText('ext_icon_crawler Crawler').click(); + await page.getByText('Crawler module').click(); } export async function openCrawlerModuleCrawlerProcesses(page) { From de51dfb7384fe31f7b0994d9970b063da2b5c427 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 18:21:20 +0100 Subject: [PATCH 18/39] update tests --- Tests/Acceptance/Tests/backend_crawler_configuration.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index 99ee8ff03..e98e34563 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -15,7 +15,7 @@ test('Able to create and save crawler configuration v13', { tag: '@v13' }, async test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page}) => { await helpers.loginBackend(page) await page.getByTitle('Records', { exact: true }).click(); - await page.locator('div.node:nth-child(2)').click(); + await page.locator('div').filter({ hasText: /^Welcome$/ }).first().click(); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'New Crawler Configuration' }).click(); await expect(page.locator('iframe[name="list_frame"]').contentFrame().locator('h1')).toContainText('Create new Crawler Configuration on page "Welcome"'); //await page.locator('iframe[name="list_frame"]').contentFrame().getByLabel('Name').click(); From 91cef5d455a5b80f8f5adebdba9cc4943b599174 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 18:49:43 +0100 Subject: [PATCH 19/39] add videos and screenshots to tests --- Tests/Acceptance/playwright.config.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Tests/Acceptance/playwright.config.js b/Tests/Acceptance/playwright.config.js index 333ba1bf6..3f19a89aa 100644 --- a/Tests/Acceptance/playwright.config.js +++ b/Tests/Acceptance/playwright.config.js @@ -32,6 +32,12 @@ module.exports = defineConfig({ /* Whether to ignore HTTPS errors when sending network requests. See https://playwright.dev/docs/api/class-testoptions#test-options-ignore-https-errors*/ ignoreHTTPSErrors: true, + + // 📸 Screenshot on failure + screenshot: 'only-on-failure', + + // 🎥 Video recording + video: 'retain-on-failure', }, /* Configure projects for major browsers */ projects: [ From 30bb126e3d2de3effc8ae521a02139f66230ae76 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 19:02:22 +0100 Subject: [PATCH 20/39] change upload path for acceptance tests --- .github/workflows/Acceptance.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index 547671e07..3f796f002 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -88,6 +88,6 @@ jobs: - uses: actions/upload-artifact@v6 if: ${{ !cancelled() }} with: - name: playwright-report - path: playwright-report/ + name: test-results + path: test-results/ retention-days: 30 From fbe265bdce622c1820201df3856099fed6286874 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 22:16:00 +0100 Subject: [PATCH 21/39] update test config --- .github/workflows/Acceptance.yml | 4 ++-- Tests/Acceptance/playwright.config.js | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index 3f796f002..547671e07 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -88,6 +88,6 @@ jobs: - uses: actions/upload-artifact@v6 if: ${{ !cancelled() }} with: - name: test-results - path: test-results/ + name: playwright-report + path: playwright-report/ retention-days: 30 diff --git a/Tests/Acceptance/playwright.config.js b/Tests/Acceptance/playwright.config.js index 3f19a89aa..dd3aa9a17 100644 --- a/Tests/Acceptance/playwright.config.js +++ b/Tests/Acceptance/playwright.config.js @@ -21,14 +21,17 @@ module.exports = defineConfig({ /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: 'dot', + reporter: [ + ['html', { outputFolder: 'playwright-report', open: 'never' }], + ['dot'], + ], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ baseURL: 'https://crawler-devbox.ddev.site/', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', + trace: 'retain-on-failure', /* Whether to ignore HTTPS errors when sending network requests. See https://playwright.dev/docs/api/class-testoptions#test-options-ignore-https-errors*/ ignoreHTTPSErrors: true, From 0d6236e4e55719fc92d01f051678f81537285635 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 22:27:50 +0100 Subject: [PATCH 22/39] update test config --- .github/workflows/Acceptance.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index 547671e07..f3a4e2ef4 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -89,5 +89,5 @@ jobs: if: ${{ !cancelled() }} with: name: playwright-report - path: playwright-report/ + path: Tests/Acceptance/playwright-report/ retention-days: 30 From 2ec4f01ff498c43e6d2374d28dc1a8a569151bb2 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Tue, 20 Jan 2026 22:32:54 +0100 Subject: [PATCH 23/39] create unique names for test results --- .github/workflows/Acceptance.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index f3a4e2ef4..28a9b7dcb 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -88,6 +88,8 @@ jobs: - uses: actions/upload-artifact@v6 if: ${{ !cancelled() }} with: - name: playwright-report - path: Tests/Acceptance/playwright-report/ + name: playwright-report-${{ matrix.typo3 }}-${{ matrix.php }} + path: Tests/Acceptance/playwright-report-${{ matrix.typo3 }}-${{ matrix.php }}/ retention-days: 30 + + From 34b989347bb54de9dd3af2ec184310aa1772db35 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 07:20:28 +0100 Subject: [PATCH 24/39] create unique names for test results --- .github/workflows/Acceptance.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index 28a9b7dcb..4a5a062fa 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -89,7 +89,7 @@ jobs: if: ${{ !cancelled() }} with: name: playwright-report-${{ matrix.typo3 }}-${{ matrix.php }} - path: Tests/Acceptance/playwright-report-${{ matrix.typo3 }}-${{ matrix.php }}/ + path: Tests/Acceptance/playwright-report/ retention-days: 30 From 6ca1eccecc262c5a45cf5610bed907a02f9e2989 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 16:11:32 +0100 Subject: [PATCH 25/39] mark test as slow --- Tests/Acceptance/Tests/backend_crawler_configuration.spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index e98e34563..2b5fceeef 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -13,6 +13,7 @@ test('Able to create and save crawler configuration v13', { tag: '@v13' }, async }); test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page}) => { + test.slow(); await helpers.loginBackend(page) await page.getByTitle('Records', { exact: true }).click(); await page.locator('div').filter({ hasText: /^Welcome$/ }).first().click(); From e8f3a6379db50f47e3b3a9a582c8557bf3571780 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 16:30:57 +0100 Subject: [PATCH 26/39] set test timeout to 120000ms --- Tests/Acceptance/Tests/backend_crawler_configuration.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index 2b5fceeef..76948e865 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -13,7 +13,7 @@ test('Able to create and save crawler configuration v13', { tag: '@v13' }, async }); test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page}) => { - test.slow(); + test.setTimeout(120000); await helpers.loginBackend(page) await page.getByTitle('Records', { exact: true }).click(); await page.locator('div').filter({ hasText: /^Welcome$/ }).first().click(); From b0a496616464a3990d21b6c0d4afd5b1a5102c85 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 16:44:00 +0100 Subject: [PATCH 27/39] try click records twice --- .github/workflows/Acceptance.yml | 2 +- Tests/Acceptance/Tests/backend_crawler_configuration.spec.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index 4a5a062fa..cb9ceac42 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -90,6 +90,6 @@ jobs: with: name: playwright-report-${{ matrix.typo3 }}-${{ matrix.php }} path: Tests/Acceptance/playwright-report/ - retention-days: 30 + retention-days: 10 diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index 76948e865..c5d6c06eb 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -16,6 +16,8 @@ test('Able to create and save crawler configuration v14', { tag: '@v14' }, async test.setTimeout(120000); await helpers.loginBackend(page) await page.getByTitle('Records', { exact: true }).click(); + await page.waitForTimeout(5000); // wait at least 5 seconds + await page.getByTitle('Records', { exact: true }).click(); await page.locator('div').filter({ hasText: /^Welcome$/ }).first().click(); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'New Crawler Configuration' }).click(); await expect(page.locator('iframe[name="list_frame"]').contentFrame().locator('h1')).toContainText('Create new Crawler Configuration on page "Welcome"'); From fe324db12da5361227d0ad9a5d88d84479ba05f3 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 16:56:34 +0100 Subject: [PATCH 28/39] debug --- .github/workflows/Acceptance.yml | 8 ++++---- .github/workflows/{DBMS.yml => DBMS.yml.disabled} | 0 .../Tests/backend_crawler_configuration.spec.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename .github/workflows/{DBMS.yml => DBMS.yml.disabled} (100%) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index cb9ceac42..a46c43d2b 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -18,9 +18,9 @@ jobs: - ^14.0 php: - '8.2' - - '8.3' - - '8.4' - - '8.5' + #- '8.3' + #- '8.4' + #- '8.5' timeout-minutes: 60 runs-on: ubuntu-24.04 @@ -82,7 +82,7 @@ jobs: - name: Install dependencies run: cd Tests/Acceptance && npm ci - name: Install Playwright Browsers - run: cd Tests/Acceptance && npx playwright install --with-deps + run: cd Tests/Acceptance && npx playwright install chromium --with-deps - name: Run Playwright tests run: cd Tests/Acceptance && npx playwright test --grep "$PW_GREP" - uses: actions/upload-artifact@v6 diff --git a/.github/workflows/DBMS.yml b/.github/workflows/DBMS.yml.disabled similarity index 100% rename from .github/workflows/DBMS.yml rename to .github/workflows/DBMS.yml.disabled diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index c5d6c06eb..b9cfebc3c 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -15,7 +15,7 @@ test('Able to create and save crawler configuration v13', { tag: '@v13' }, async test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page}) => { test.setTimeout(120000); await helpers.loginBackend(page) - await page.getByTitle('Records', { exact: true }).click(); + await page.getByTitle('TypoScript', { exact: true }).click(); await page.waitForTimeout(5000); // wait at least 5 seconds await page.getByTitle('Records', { exact: true }).click(); await page.locator('div').filter({ hasText: /^Welcome$/ }).first().click(); From 9e7364516758c441ae0dc2d6fdf5b1b04d3b22b0 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 17:13:52 +0100 Subject: [PATCH 29/39] adjust test --- .../backend_crawler_configuration.spec.js | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index b9cfebc3c..053401b56 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -11,12 +11,9 @@ test('Able to create and save crawler configuration v13', { tag: '@v13' }, async await page.locator('iframe[name="list_frame"]').contentFrame().getByLabel('Name').fill('Test Configuration'); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'Save' }).click(); }); - +/* test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page}) => { - test.setTimeout(120000); await helpers.loginBackend(page) - await page.getByTitle('TypoScript', { exact: true }).click(); - await page.waitForTimeout(5000); // wait at least 5 seconds await page.getByTitle('Records', { exact: true }).click(); await page.locator('div').filter({ hasText: /^Welcome$/ }).first().click(); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'New Crawler Configuration' }).click(); @@ -25,3 +22,32 @@ test('Able to create and save crawler configuration v14', { tag: '@v14' }, async await page.locator('iframe[name="list_frame"]').contentFrame().getByLabel('Name').fill('Test Configuration'); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'Save' }).click(); }); +*/ + +test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page }) => { + await helpers.loginBackend(page); + + // Ensure backend navigation is ready + await page.getByTitle('Records', { exact: true }).waitFor(); + + await page.getByTitle('Records', { exact: true }).click(); + await page.locator('div').filter({ hasText: /^Welcome$/ }).first().click(); + + const listFrameLocator = page.locator('iframe[name="list_frame"]'); + await listFrameLocator.waitFor({ state: 'attached' }); + + const listFrame = await listFrameLocator.contentFrame(); + if (!listFrame) throw new Error('list_frame not available'); + + await listFrame.getByRole('button', { name: 'New Crawler Configuration' }).waitFor(); + await listFrame.getByRole('button', { name: 'New Crawler Configuration' }).click(); + + await expect( + listFrame.locator('h1') + ).toContainText('Create new Crawler Configuration on page "Welcome"'); + + await listFrame.getByLabel('Name').fill('Test Configuration'); + await listFrame.getByRole('button', { name: 'Save' }).click(); +}); + + From d35cafaf6e8740fedeae6e9a38a07498f95bd775 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 17:25:31 +0100 Subject: [PATCH 30/39] debug --- .../backend_crawler_configuration.spec.js | 25 +++++++++++++++++++ Tests/Acceptance/playwright.config.js | 8 ++++++ 2 files changed, 33 insertions(+) diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index 053401b56..857e4ebf5 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -27,6 +27,25 @@ test('Able to create and save crawler configuration v14', { tag: '@v14' }, async test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page }) => { await helpers.loginBackend(page); + + page.on('console', msg => + console.log('[console]', msg.type(), msg.text()) + ); + + page.on('pageerror', err => + console.log('[pageerror]', err.message) + ); + + page.on('requestfailed', req => + console.log('[requestfailed]', req.url(), req.failure()?.errorText) + ); + + page.on('response', res => { + if (res.status() >= 400) { + console.log('[response]', res.status(), res.url()); + } + }); + // Ensure backend navigation is ready await page.getByTitle('Records', { exact: true }).waitFor(); @@ -50,4 +69,10 @@ test('Able to create and save crawler configuration v14', { tag: '@v14' }, async await listFrame.getByRole('button', { name: 'Save' }).click(); }); +test('backend loads without interaction', async ({ page }) => { + await helpers.loginBackend(page); + await page.waitForSelector('iframe[name="nav_frame"]', { timeout: 30_000 }); + await page.waitForSelector('iframe[name="list_frame"]', { timeout: 30_000 }); +}); + diff --git a/Tests/Acceptance/playwright.config.js b/Tests/Acceptance/playwright.config.js index dd3aa9a17..b9da93053 100644 --- a/Tests/Acceptance/playwright.config.js +++ b/Tests/Acceptance/playwright.config.js @@ -41,6 +41,14 @@ module.exports = defineConfig({ // 🎥 Video recording video: 'retain-on-failure', + + browserName: 'chromium', + launchOptions: { + args: [ + '--no-sandbox', + '--disable-dev-shm-usage', + ], + }, }, /* Configure projects for major browsers */ projects: [ From 7575804c94b37bc61548c35f654f62c53fa937af Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 17:32:11 +0100 Subject: [PATCH 31/39] add missing tag --- Tests/Acceptance/Tests/backend_crawler_configuration.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index 857e4ebf5..4bea0ea6e 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -69,7 +69,7 @@ test('Able to create and save crawler configuration v14', { tag: '@v14' }, async await listFrame.getByRole('button', { name: 'Save' }).click(); }); -test('backend loads without interaction', async ({ page }) => { +test('backend loads without interaction', { tag: '@v14' },async ({ page }) => { await helpers.loginBackend(page); await page.waitForSelector('iframe[name="nav_frame"]', { timeout: 30_000 }); await page.waitForSelector('iframe[name="list_frame"]', { timeout: 30_000 }); From 1fc2dcabfc74b51eed918271fee4d8ae79617c2a Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 17:32:53 +0100 Subject: [PATCH 32/39] add missing tag --- .github/workflows/Acceptance.yml | 2 +- Tests/Acceptance/Tests/backend_crawler_configuration.spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index a46c43d2b..2982ee9e5 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -41,7 +41,7 @@ jobs: if [[ "${{ matrix.typo3 }}" == "^13.4" ]]; then echo "PW_GREP=@v13" >> $GITHUB_ENV elif [[ "${{ matrix.typo3 }}" == "^14.0" ]]; then - echo "PW_GREP=@v14" >> $GITHUB_ENV + echo "PW_GREP=@wip" >> $GITHUB_ENV fi - uses: actions/checkout@v6 diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index 4bea0ea6e..e0a106f3a 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -24,7 +24,7 @@ test('Able to create and save crawler configuration v14', { tag: '@v14' }, async }); */ -test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page }) => { +test('Able to create and save crawler configuration v14', { tag: '@wip' }, async ({ page }) => { await helpers.loginBackend(page); @@ -69,7 +69,7 @@ test('Able to create and save crawler configuration v14', { tag: '@v14' }, async await listFrame.getByRole('button', { name: 'Save' }).click(); }); -test('backend loads without interaction', { tag: '@v14' },async ({ page }) => { +test('backend loads without interaction', { tag: '@wip' },async ({ page }) => { await helpers.loginBackend(page); await page.waitForSelector('iframe[name="nav_frame"]', { timeout: 30_000 }); await page.waitForSelector('iframe[name="list_frame"]', { timeout: 30_000 }); From 8aa9b07d59f65ea3f3a9aee93cc45b5bdc5ec3da Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 17:46:48 +0100 Subject: [PATCH 33/39] upload typo3logs --- .devbox/config/system/additional.php | 9 +++++++++ .github/workflows/Acceptance.yml | 15 +++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/.devbox/config/system/additional.php b/.devbox/config/system/additional.php index 6754e27e1..8d23abb92 100644 --- a/.devbox/config/system/additional.php +++ b/.devbox/config/system/additional.php @@ -6,6 +6,15 @@ * It is recommended that you leave this file alone. */ +$GLOBALS['TYPO3_CONF_VARS']['LOG']['writerConfiguration'] = [ + \TYPO3\CMS\Core\Log\LogLevel::DEBUG => [ + \TYPO3\CMS\Core\Log\Writer\FileWriter::class => [ + 'logFile' => 'var/log/ci-typo3.log', + ], + ], +]; + + if (getenv('IS_DDEV_PROJECT') == 'true') { $GLOBALS['TYPO3_CONF_VARS'] = array_replace_recursive( $GLOBALS['TYPO3_CONF_VARS'], diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index 2982ee9e5..96a3025b4 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -44,6 +44,12 @@ jobs: echo "PW_GREP=@wip" >> $GITHUB_ENV fi + - name: debug + run: | + echo "display_errors=On" >> /usr/local/etc/php/conf.d/ci.ini + echo "display_startup_errors=On" >> /usr/local/etc/php/conf.d/ci.ini + echo "error_reporting=E_ALL" >> /usr/local/etc/php/conf.d/ci.ini + - uses: actions/checkout@v6 - name: Patch composer.json for forked PR if: > @@ -92,4 +98,13 @@ jobs: path: Tests/Acceptance/playwright-report/ retention-days: 10 + - name: Upload TYPO3 logs + if: ${{ !cancelled() }} + uses: actions/upload-artifact@v6 + with: + name: typo3-logs-${{ matrix.typo3 }}-${{ matrix.php }} + path: | + .devbox/var/log/ + + From 9f9e40fe4bdf4e9c06ebaecd467437ab190f257d Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 17:48:27 +0100 Subject: [PATCH 34/39] remove php-ini settings --- .github/workflows/Acceptance.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index 96a3025b4..49ba1e46a 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -44,12 +44,6 @@ jobs: echo "PW_GREP=@wip" >> $GITHUB_ENV fi - - name: debug - run: | - echo "display_errors=On" >> /usr/local/etc/php/conf.d/ci.ini - echo "display_startup_errors=On" >> /usr/local/etc/php/conf.d/ci.ini - echo "error_reporting=E_ALL" >> /usr/local/etc/php/conf.d/ci.ini - - uses: actions/checkout@v6 - name: Patch composer.json for forked PR if: > From 5b03385f5f6f90e68e1ec1d1e5a9757bc5788e00 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 17:59:32 +0100 Subject: [PATCH 35/39] cleanup --- .devbox/config/system/additional.php | 9 --- .github/workflows/Acceptance.yml | 17 +----- .../workflows/{DBMS.yml.disabled => DBMS.yml} | 0 .../backend_crawler_configuration.spec.js | 58 +------------------ 4 files changed, 5 insertions(+), 79 deletions(-) rename .github/workflows/{DBMS.yml.disabled => DBMS.yml} (100%) diff --git a/.devbox/config/system/additional.php b/.devbox/config/system/additional.php index 8d23abb92..6754e27e1 100644 --- a/.devbox/config/system/additional.php +++ b/.devbox/config/system/additional.php @@ -6,15 +6,6 @@ * It is recommended that you leave this file alone. */ -$GLOBALS['TYPO3_CONF_VARS']['LOG']['writerConfiguration'] = [ - \TYPO3\CMS\Core\Log\LogLevel::DEBUG => [ - \TYPO3\CMS\Core\Log\Writer\FileWriter::class => [ - 'logFile' => 'var/log/ci-typo3.log', - ], - ], -]; - - if (getenv('IS_DDEV_PROJECT') == 'true') { $GLOBALS['TYPO3_CONF_VARS'] = array_replace_recursive( $GLOBALS['TYPO3_CONF_VARS'], diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index 49ba1e46a..f364f1b49 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -18,9 +18,9 @@ jobs: - ^14.0 php: - '8.2' - #- '8.3' - #- '8.4' - #- '8.5' + - '8.3' + - '8.4' + - '8.5' timeout-minutes: 60 runs-on: ubuntu-24.04 @@ -91,14 +91,3 @@ jobs: name: playwright-report-${{ matrix.typo3 }}-${{ matrix.php }} path: Tests/Acceptance/playwright-report/ retention-days: 10 - - - name: Upload TYPO3 logs - if: ${{ !cancelled() }} - uses: actions/upload-artifact@v6 - with: - name: typo3-logs-${{ matrix.typo3 }}-${{ matrix.php }} - path: | - .devbox/var/log/ - - - diff --git a/.github/workflows/DBMS.yml.disabled b/.github/workflows/DBMS.yml similarity index 100% rename from .github/workflows/DBMS.yml.disabled rename to .github/workflows/DBMS.yml diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index e0a106f3a..d6669be94 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -11,8 +11,8 @@ test('Able to create and save crawler configuration v13', { tag: '@v13' }, async await page.locator('iframe[name="list_frame"]').contentFrame().getByLabel('Name').fill('Test Configuration'); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'Save' }).click(); }); -/* -test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page}) => { + +test('Able to create and save crawler configuration v14', { tag: '@wip' }, async ({ page}) => { await helpers.loginBackend(page) await page.getByTitle('Records', { exact: true }).click(); await page.locator('div').filter({ hasText: /^Welcome$/ }).first().click(); @@ -22,57 +22,3 @@ test('Able to create and save crawler configuration v14', { tag: '@v14' }, async await page.locator('iframe[name="list_frame"]').contentFrame().getByLabel('Name').fill('Test Configuration'); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'Save' }).click(); }); -*/ - -test('Able to create and save crawler configuration v14', { tag: '@wip' }, async ({ page }) => { - await helpers.loginBackend(page); - - - page.on('console', msg => - console.log('[console]', msg.type(), msg.text()) - ); - - page.on('pageerror', err => - console.log('[pageerror]', err.message) - ); - - page.on('requestfailed', req => - console.log('[requestfailed]', req.url(), req.failure()?.errorText) - ); - - page.on('response', res => { - if (res.status() >= 400) { - console.log('[response]', res.status(), res.url()); - } - }); - - // Ensure backend navigation is ready - await page.getByTitle('Records', { exact: true }).waitFor(); - - await page.getByTitle('Records', { exact: true }).click(); - await page.locator('div').filter({ hasText: /^Welcome$/ }).first().click(); - - const listFrameLocator = page.locator('iframe[name="list_frame"]'); - await listFrameLocator.waitFor({ state: 'attached' }); - - const listFrame = await listFrameLocator.contentFrame(); - if (!listFrame) throw new Error('list_frame not available'); - - await listFrame.getByRole('button', { name: 'New Crawler Configuration' }).waitFor(); - await listFrame.getByRole('button', { name: 'New Crawler Configuration' }).click(); - - await expect( - listFrame.locator('h1') - ).toContainText('Create new Crawler Configuration on page "Welcome"'); - - await listFrame.getByLabel('Name').fill('Test Configuration'); - await listFrame.getByRole('button', { name: 'Save' }).click(); -}); - -test('backend loads without interaction', { tag: '@wip' },async ({ page }) => { - await helpers.loginBackend(page); - await page.waitForSelector('iframe[name="nav_frame"]', { timeout: 30_000 }); - await page.waitForSelector('iframe[name="list_frame"]', { timeout: 30_000 }); -}); - - From 1859aafa847e3c87b1554d3f2be71be8c976798b Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 19:02:06 +0100 Subject: [PATCH 36/39] test with firefox and webkit in ci to test if a difference --- .github/workflows/Acceptance.yml | 2 +- Tests/Acceptance/Tests/backend_crawler_configuration.spec.js | 2 +- Tests/Acceptance/playwright.config.js | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index f364f1b49..bfca71b0b 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -41,7 +41,7 @@ jobs: if [[ "${{ matrix.typo3 }}" == "^13.4" ]]; then echo "PW_GREP=@v13" >> $GITHUB_ENV elif [[ "${{ matrix.typo3 }}" == "^14.0" ]]; then - echo "PW_GREP=@wip" >> $GITHUB_ENV + echo "PW_GREP=@v14" >> $GITHUB_ENV fi - uses: actions/checkout@v6 diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index d6669be94..e98e34563 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -12,7 +12,7 @@ test('Able to create and save crawler configuration v13', { tag: '@v13' }, async await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'Save' }).click(); }); -test('Able to create and save crawler configuration v14', { tag: '@wip' }, async ({ page}) => { +test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page}) => { await helpers.loginBackend(page) await page.getByTitle('Records', { exact: true }).click(); await page.locator('div').filter({ hasText: /^Welcome$/ }).first().click(); diff --git a/Tests/Acceptance/playwright.config.js b/Tests/Acceptance/playwright.config.js index b9da93053..7b525b41f 100644 --- a/Tests/Acceptance/playwright.config.js +++ b/Tests/Acceptance/playwright.config.js @@ -56,7 +56,6 @@ module.exports = defineConfig({ name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, -/* { name: 'firefox', use: { ...devices['Desktop Firefox'] }, @@ -65,7 +64,7 @@ module.exports = defineConfig({ { name: 'webkit', use: { ...devices['Desktop Safari'] }, - },*/ + }, ], /* Run your local dev server before starting the tests */ From 14d644b7a4ab7f7efef7491c9a8d04908db4086f Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 19:04:49 +0100 Subject: [PATCH 37/39] remove install only chromium --- .github/workflows/Acceptance.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index bfca71b0b..b99c2bace 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -82,7 +82,7 @@ jobs: - name: Install dependencies run: cd Tests/Acceptance && npm ci - name: Install Playwright Browsers - run: cd Tests/Acceptance && npx playwright install chromium --with-deps + run: cd Tests/Acceptance && npx playwright install --with-deps - name: Run Playwright tests run: cd Tests/Acceptance && npx playwright test --grep "$PW_GREP" - uses: actions/upload-artifact@v6 From e38c7960def2cf9cc064cc3fbbac3ba05d346ed8 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 19:27:54 +0100 Subject: [PATCH 38/39] debug --- .github/workflows/Acceptance.yml | 8 +++++ .../backend_crawler_configuration.spec.js | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index b99c2bace..eced53926 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -85,6 +85,14 @@ jobs: run: cd Tests/Acceptance && npx playwright install --with-deps - name: Run Playwright tests run: cd Tests/Acceptance && npx playwright test --grep "$PW_GREP" + + - name: Output TYPO3 Logs on failure + if: failure() + run: | + echo "--- TYPO3 LOGS ---" + ddev exec "cat var/log/typo3_*.log" || echo "No logs found" + echo "--- DDEV LOGS ---" + ddev logs - uses: actions/upload-artifact@v6 if: ${{ !cancelled() }} with: diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index e98e34563..455eeba38 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -15,6 +15,7 @@ test('Able to create and save crawler configuration v13', { tag: '@v13' }, async test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page}) => { await helpers.loginBackend(page) await page.getByTitle('Records', { exact: true }).click(); + await page.waitForLoadState('networkidle'); await page.locator('div').filter({ hasText: /^Welcome$/ }).first().click(); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'New Crawler Configuration' }).click(); await expect(page.locator('iframe[name="list_frame"]').contentFrame().locator('h1')).toContainText('Create new Crawler Configuration on page "Welcome"'); @@ -22,3 +23,31 @@ test('Able to create and save crawler configuration v14', { tag: '@v14' }, async await page.locator('iframe[name="list_frame"]').contentFrame().getByLabel('Name').fill('Test Configuration'); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'Save' }).click(); }); + +test('Able to create and save crawler configuration v14 v2', { tag: '@v14' }, async ({ page }) => { + await helpers.loginBackend(page); + + // 1. Click Records and wait for the URL to stabilize + await page.getByTitle('Records', { exact: true }).click(); + + // 2. Ensure the "Navigation loading error" toast isn't visible + // This acts as a 'guard'—if it appears, the test fails immediately with a clear reason + await expect(page.locator('.typo3-module-menu')).toBeVisible(); + await expect(page.getByText('Navigation loading error')).not.toBeVisible(); + + // 3. Click "Welcome" in the tree (Wait for it to be visible first) + const welcomeNode = page.locator('div').filter({ hasText: /^Welcome$/ }).first(); + await welcomeNode.waitFor({ state: 'visible' }); + await welcomeNode.click(); + + // 4. Use the modern frameLocator API + const listFrame = page.frameLocator('iframe[name="list_frame"]'); + + const newConfigBtn = listFrame.getByRole('button', { name: 'New Crawler Configuration' }); + await newConfigBtn.click(); + + await expect(listFrame.locator('h1')).toContainText('Create new Crawler Configuration on page "Welcome"'); + + await listFrame.getByLabel('Name').fill('Test Configuration'); + await listFrame.getByRole('button', { name: 'Save' }).click(); +}); From 9a04b988e3a45d21b9505ccb12123f02781b9296 Mon Sep 17 00:00:00 2001 From: Tomas Norre Mikkelsen Date: Wed, 21 Jan 2026 19:45:03 +0100 Subject: [PATCH 39/39] disabled wip tests --- .github/workflows/Acceptance.yml | 10 +----- .../backend_crawler_configuration.spec.js | 32 ++----------------- Tests/Acceptance/playwright.config.js | 2 ++ 3 files changed, 5 insertions(+), 39 deletions(-) diff --git a/.github/workflows/Acceptance.yml b/.github/workflows/Acceptance.yml index eced53926..bfca71b0b 100644 --- a/.github/workflows/Acceptance.yml +++ b/.github/workflows/Acceptance.yml @@ -82,17 +82,9 @@ jobs: - name: Install dependencies run: cd Tests/Acceptance && npm ci - name: Install Playwright Browsers - run: cd Tests/Acceptance && npx playwright install --with-deps + run: cd Tests/Acceptance && npx playwright install chromium --with-deps - name: Run Playwright tests run: cd Tests/Acceptance && npx playwright test --grep "$PW_GREP" - - - name: Output TYPO3 Logs on failure - if: failure() - run: | - echo "--- TYPO3 LOGS ---" - ddev exec "cat var/log/typo3_*.log" || echo "No logs found" - echo "--- DDEV LOGS ---" - ddev logs - uses: actions/upload-artifact@v6 if: ${{ !cancelled() }} with: diff --git a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js index 455eeba38..2da7648ff 100644 --- a/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js +++ b/Tests/Acceptance/Tests/backend_crawler_configuration.spec.js @@ -1,7 +1,7 @@ import { test, expect } from '@playwright/test'; import * as helpers from './helpers'; -test('Able to create and save crawler configuration v13', { tag: '@v13' }, async ({ page}) => { +test('Able to create and save crawler configuration TYPO3-13', { tag: '@v13' }, async ({ page}) => { await helpers.loginBackend(page) await page.getByTitle('List', { exact: true }).click(); await page.locator('div.node:nth-child(2)').click(); @@ -12,7 +12,7 @@ test('Able to create and save crawler configuration v13', { tag: '@v13' }, async await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'Save' }).click(); }); -test('Able to create and save crawler configuration v14', { tag: '@v14' }, async ({ page}) => { +test('Able to create and save crawler configuration TYPO3-14', { tag: '@wip' }, async ({ page}) => { await helpers.loginBackend(page) await page.getByTitle('Records', { exact: true }).click(); await page.waitForLoadState('networkidle'); @@ -23,31 +23,3 @@ test('Able to create and save crawler configuration v14', { tag: '@v14' }, async await page.locator('iframe[name="list_frame"]').contentFrame().getByLabel('Name').fill('Test Configuration'); await page.locator('iframe[name="list_frame"]').contentFrame().getByRole('button', { name: 'Save' }).click(); }); - -test('Able to create and save crawler configuration v14 v2', { tag: '@v14' }, async ({ page }) => { - await helpers.loginBackend(page); - - // 1. Click Records and wait for the URL to stabilize - await page.getByTitle('Records', { exact: true }).click(); - - // 2. Ensure the "Navigation loading error" toast isn't visible - // This acts as a 'guard'—if it appears, the test fails immediately with a clear reason - await expect(page.locator('.typo3-module-menu')).toBeVisible(); - await expect(page.getByText('Navigation loading error')).not.toBeVisible(); - - // 3. Click "Welcome" in the tree (Wait for it to be visible first) - const welcomeNode = page.locator('div').filter({ hasText: /^Welcome$/ }).first(); - await welcomeNode.waitFor({ state: 'visible' }); - await welcomeNode.click(); - - // 4. Use the modern frameLocator API - const listFrame = page.frameLocator('iframe[name="list_frame"]'); - - const newConfigBtn = listFrame.getByRole('button', { name: 'New Crawler Configuration' }); - await newConfigBtn.click(); - - await expect(listFrame.locator('h1')).toContainText('Create new Crawler Configuration on page "Welcome"'); - - await listFrame.getByLabel('Name').fill('Test Configuration'); - await listFrame.getByRole('button', { name: 'Save' }).click(); -}); diff --git a/Tests/Acceptance/playwright.config.js b/Tests/Acceptance/playwright.config.js index 7b525b41f..417c73e34 100644 --- a/Tests/Acceptance/playwright.config.js +++ b/Tests/Acceptance/playwright.config.js @@ -56,6 +56,7 @@ module.exports = defineConfig({ name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, + /* { name: 'firefox', use: { ...devices['Desktop Firefox'] }, @@ -65,6 +66,7 @@ module.exports = defineConfig({ name: 'webkit', use: { ...devices['Desktop Safari'] }, }, + */ ], /* Run your local dev server before starting the tests */