diff --git a/.gitleaksignore b/.gitleaksignore new file mode 100644 index 0000000..5467af4 --- /dev/null +++ b/.gitleaksignore @@ -0,0 +1,8 @@ +# Test fixtures, not real secrets: TYPO3 SYS.encryptionKey values used only in unit tests. +# Migrating ConfigurationTest to ttt's #[WithTypo3ConfVars] turned the previous +# $GLOBALS[...]['encryptionKey'] = '...' assignment into an array-arrow literal, which trips +# gitleaks' generic-api-key rule where the bracket assignment did not. The literals are the +# obviously-fake string "test-encryption-key-12345"; the HEAD occurrences also carry an inline +# `gitleaks:allow`, these fingerprints cover the same lines in the historical integration commit. +f9381041121ecaefabe744efa9b3014d2446277b:Tests/Unit/ConfigurationTest.php:generic-api-key:56 +f9381041121ecaefabe744efa9b3014d2446277b:Tests/Unit/ConfigurationTest.php:generic-api-key:70 diff --git a/Tests/Unit/Configuration/DetectorConfigurationBuilderTest.php b/Tests/Unit/Configuration/DetectorConfigurationBuilderTest.php index 89b23c4..c633266 100644 --- a/Tests/Unit/Configuration/DetectorConfigurationBuilderTest.php +++ b/Tests/Unit/Configuration/DetectorConfigurationBuilderTest.php @@ -14,6 +14,7 @@ namespace MoveElevator\Typo3LoginWarning\Tests\Unit\Configuration; use Exception; +use KonradMichalik\Ttt\Attribute\WithTypo3ConfVars; use MoveElevator\Typo3LoginWarning\Configuration; use MoveElevator\Typo3LoginWarning\Configuration\DetectorConfigurationBuilder; use MoveElevator\Typo3LoginWarning\Detector\{LongTimeNoSeeDetector, NewIpDetector, OutOfOfficeDetector}; @@ -29,6 +30,7 @@ * @author Konrad Michalik * @license GPL-2.0-or-later */ +#[WithTypo3ConfVars(['EXTENSIONS' => [Configuration::EXT_KEY => []]])] final class DetectorConfigurationBuilderTest extends TestCase { private ExtensionConfiguration&MockObject $extensionConfiguration; @@ -44,12 +46,6 @@ protected function setUp(): void $this->extensionConfiguration = $this->createMock(ExtensionConfiguration::class); $this->subject = new DetectorConfigurationBuilder($this->extensionConfiguration); - $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS'][Configuration::EXT_KEY] = []; - } - - protected function tearDown(): void - { - unset($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS'][Configuration::EXT_KEY]); } public function testIsActiveReturnsTrueWhenDetectorIsActive(): void @@ -186,6 +182,7 @@ public function testBuildLongTimeNoSeeConfigWithCustomValues(): void ], $result); } + #[WithTypo3ConfVars(['SYS' => ['phpTimeZone' => 'Europe/Berlin']])] public function testBuildOutOfOfficeConfigWithDefaults(): void { $this->extensionConfiguration @@ -193,8 +190,6 @@ public function testBuildOutOfOfficeConfigWithDefaults(): void ->with(Configuration::EXT_KEY) ->willReturn(['outOfOffice' => ['active' => true]]); - $GLOBALS['TYPO3_CONF_VARS']['SYS']['phpTimeZone'] = 'Europe/Berlin'; - $result = $this->subject->build(OutOfOfficeDetector::class); self::assertSame('Europe/Berlin', $result['timezone']); @@ -253,6 +248,7 @@ public function testBuildOutOfOfficeConfigWithBlockedPeriods(): void ], $result['blockedPeriods']); } + #[WithTypo3ConfVars(['BE' => ['warning_email_addr' => 'admin@example.com']])] public function testBuildNotificationConfigWithDefaults(): void { $this->extensionConfiguration @@ -260,8 +256,6 @@ public function testBuildNotificationConfigWithDefaults(): void ->with(Configuration::EXT_KEY) ->willReturn([]); - $GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr'] = 'admin@example.com'; - $result = $this->subject->buildNotificationConfig(); self::assertSame('admin@example.com', $result['recipient']); diff --git a/Tests/Unit/ConfigurationTest.php b/Tests/Unit/ConfigurationTest.php index 37cb989..2a4d26f 100644 --- a/Tests/Unit/ConfigurationTest.php +++ b/Tests/Unit/ConfigurationTest.php @@ -13,6 +13,7 @@ namespace MoveElevator\Typo3LoginWarning\Tests\Unit; +use KonradMichalik\Ttt\Attribute\WithTypo3ConfVars; use MoveElevator\Typo3LoginWarning\Configuration; use PHPUnit\Framework\TestCase; @@ -22,15 +23,9 @@ * @author Konrad Michalik * @license GPL-2.0-or-later */ +#[WithTypo3ConfVars([])] final class ConfigurationTest extends TestCase { - protected function tearDown(): void - { - // Clean up global state - unset($GLOBALS['TYPO3_CONF_VARS']['MAIL']['templateRootPaths'][500]); - unset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][Configuration::EXT_KEY]); - } - public function testExtKeyConstant(): void { self::assertSame('typo3_login_warning', Configuration::EXT_KEY); @@ -58,9 +53,9 @@ public function testRegisterMailTemplateAddsTemplateRootPath(): void ); } + #[WithTypo3ConfVars(['SYS' => ['encryptionKey' => 'test-encryption-key-12345']])] // gitleaks:allow public function testRegisterHmacKeyUsesEncryptionKeyWhenNotSet(): void { - $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = 'test-encryption-key-12345'; unset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][Configuration::EXT_KEY]['hmacKey']); Configuration::registerHmacKey(); @@ -71,11 +66,12 @@ public function testRegisterHmacKeyUsesEncryptionKeyWhenNotSet(): void ); } + #[WithTypo3ConfVars([ + 'SYS' => ['encryptionKey' => 'test-encryption-key-12345'], // gitleaks:allow + 'EXTCONF' => [Configuration::EXT_KEY => ['hmacKey' => 'existing-hmac-key']], + ])] public function testRegisterHmacKeyDoesNotOverwriteExistingKey(): void { - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][Configuration::EXT_KEY]['hmacKey'] = 'existing-hmac-key'; - $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = 'test-encryption-key-12345'; - Configuration::registerHmacKey(); self::assertSame( diff --git a/Tests/Unit/Detector/AbstractDetectorTest.php b/Tests/Unit/Detector/AbstractDetectorTest.php index c690a46..3aaa0d1 100644 --- a/Tests/Unit/Detector/AbstractDetectorTest.php +++ b/Tests/Unit/Detector/AbstractDetectorTest.php @@ -13,6 +13,7 @@ namespace MoveElevator\Typo3LoginWarning\Tests\Unit\Detector; +use KonradMichalik\Ttt\Attribute\WithTypo3ConfVars; use MoveElevator\Typo3LoginWarning\Detector\AbstractDetector; use PHPUnit\Framework\TestCase; @@ -52,17 +53,17 @@ public function testShouldDetectForUserReturnsFalseForNonAdminWhenAffectedUsersI self::assertFalse($this->subject->exposeShouldDetectForUser($userArray, ['affectedUsers' => 'admins'])); } + #[WithTypo3ConfVars(['SYS' => ['systemMaintainers' => [1, 2]]])] public function testShouldDetectForUserReturnsTrueForSystemMaintainerWhenAffectedUsersIsMaintainers(): void { - $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers'] = [1, 2]; $userArray = $this->createUserArray(uid: 1); self::assertTrue($this->subject->exposeShouldDetectForUser($userArray, ['affectedUsers' => 'maintainers'])); } + #[WithTypo3ConfVars(['SYS' => ['systemMaintainers' => [2, 3]]])] public function testShouldDetectForUserReturnsFalseForNonSystemMaintainerWhenAffectedUsersIsMaintainers(): void { - $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers'] = [2, 3]; $userArray = $this->createUserArray(uid: 1); self::assertFalse($this->subject->exposeShouldDetectForUser($userArray, ['affectedUsers' => 'maintainers'])); diff --git a/Tests/Unit/Detector/LongTimeNoSeeDetectorTest.php b/Tests/Unit/Detector/LongTimeNoSeeDetectorTest.php index 37fb08e..4466126 100644 --- a/Tests/Unit/Detector/LongTimeNoSeeDetectorTest.php +++ b/Tests/Unit/Detector/LongTimeNoSeeDetectorTest.php @@ -14,6 +14,7 @@ namespace MoveElevator\Typo3LoginWarning\Tests\Unit\Detector; use DateTime; +use KonradMichalik\Ttt\Attribute\WithTypo3ConfVars; use MoveElevator\Typo3LoginWarning\Configuration; use MoveElevator\Typo3LoginWarning\Detector\{DetectorInterface, LongTimeNoSeeDetector}; use PHPUnit\Framework\TestCase; @@ -384,10 +385,9 @@ public function testShouldDetectForUserReturnsTrueForAdmin(): void self::assertTrue($result); } + #[WithTypo3ConfVars(['SYS' => ['systemMaintainers' => [2, 3]]])] public function testShouldDetectForUserReturnsFalseForNonMaintainer(): void { - $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers'] = [2, 3]; - $user = $this->createMockUser(['uid' => 123]); $configuration = ['affectedUsers' => 'maintainers']; @@ -396,14 +396,11 @@ public function testShouldDetectForUserReturnsFalseForNonMaintainer(): void $result = $subject->shouldDetectForUser($user, $configuration); self::assertFalse($result); - - unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers']); } + #[WithTypo3ConfVars(['SYS' => ['systemMaintainers' => [123, 456]]])] public function testShouldDetectForUserReturnsTrueForMaintainer(): void { - $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers'] = [123, 456]; - $user = $this->createMockUser(['uid' => 123]); $configuration = ['affectedUsers' => 'maintainers']; @@ -412,8 +409,6 @@ public function testShouldDetectForUserReturnsTrueForMaintainer(): void $result = $subject->shouldDetectForUser($user, $configuration); self::assertTrue($result); - - unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers']); } /** diff --git a/Tests/Unit/Detector/NewIpDetectorTest.php b/Tests/Unit/Detector/NewIpDetectorTest.php index aabca87..192862b 100644 --- a/Tests/Unit/Detector/NewIpDetectorTest.php +++ b/Tests/Unit/Detector/NewIpDetectorTest.php @@ -13,6 +13,7 @@ namespace MoveElevator\Typo3LoginWarning\Tests\Unit\Detector; +use KonradMichalik\Ttt\Attribute\WithTypo3ConfVars; use MoveElevator\Typo3LoginWarning\Detector\{DetectorInterface, NewIpDetector}; use MoveElevator\Typo3LoginWarning\Domain\Repository\IpLogRepository; use MoveElevator\Typo3LoginWarning\Service\GeolocationServiceInterface; @@ -26,20 +27,18 @@ * @author Konrad Michalik * @license GPL-2.0-or-later */ +#[WithTypo3ConfVars(['SYS' => ['encryptionKey' => 'test-encryption-key-for-phpunit']])] final class NewIpDetectorTest extends TestCase { protected function setUp(): void { // Clean slate for each test - set default to avoid issues $GLOBALS['_SERVER']['REMOTE_ADDR'] = '127.0.0.1'; - // Set HMAC key for tests - $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = 'test-encryption-key-for-phpunit'; } protected function tearDown(): void { unset($GLOBALS['_SERVER']['REMOTE_ADDR']); - unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']); } public function testImplementsDetectorInterface(): void @@ -241,10 +240,9 @@ public function testShouldDetectForUserReturnsTrueForAdmin(): void self::assertTrue($result); } + #[WithTypo3ConfVars(['SYS' => ['systemMaintainers' => [2, 3]]])] public function testShouldDetectForUserReturnsFalseForNonMaintainer(): void { - $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers'] = [2, 3]; - $user = $this->createMockUser(['uid' => 123]); $configuration = ['affectedUsers' => 'maintainers']; @@ -253,14 +251,11 @@ public function testShouldDetectForUserReturnsFalseForNonMaintainer(): void $result = $subject->shouldDetectForUser($user, $configuration); self::assertFalse($result); - - unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers']); } + #[WithTypo3ConfVars(['SYS' => ['systemMaintainers' => [123, 456]]])] public function testShouldDetectForUserReturnsTrueForMaintainer(): void { - $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers'] = [123, 456]; - $user = $this->createMockUser(['uid' => 123]); $configuration = ['affectedUsers' => 'maintainers']; @@ -269,8 +264,6 @@ public function testShouldDetectForUserReturnsTrueForMaintainer(): void $result = $subject->shouldDetectForUser($user, $configuration); self::assertTrue($result); - - unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers']); } public function testDetectAddsDeviceInfoWhenEnabled(): void diff --git a/Tests/Unit/Notification/EmailNotificationTest.php b/Tests/Unit/Notification/EmailNotificationTest.php index 6513fd4..1f193f1 100644 --- a/Tests/Unit/Notification/EmailNotificationTest.php +++ b/Tests/Unit/Notification/EmailNotificationTest.php @@ -13,6 +13,7 @@ namespace MoveElevator\Typo3LoginWarning\Tests\Unit\Notification; +use KonradMichalik\Ttt\Attribute\WithTypo3ConfVars; use MoveElevator\Typo3LoginWarning\Notification\{EmailNotification, NotifierInterface}; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -29,6 +30,7 @@ * @author Konrad Michalik * @license GPL-2.0-or-later */ +#[WithTypo3ConfVars(['BE' => ['warning_email_addr' => '']])] final class EmailNotificationTest extends TestCase { private MailerInterface&MockObject $mailer; @@ -44,9 +46,6 @@ protected function setUp(): void $this->subject = new EmailNotification($this->mailer); $this->subject->setLogger($this->logger); - - // Initialize TYPO3_CONF_VARS to prevent warnings - $GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr'] = ''; } public function testImplementsNotifierInterface(): void @@ -71,8 +70,6 @@ public function testNotifyLogsInfoWhenNoRecipientConfigured(): void $user = $this->createMockBackendUser(['uid' => 123]); $configuration = []; - $GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr'] = ''; - $this->logger ->expects(self::once()) ->method('info') @@ -101,13 +98,12 @@ public function testNotifyUsesConfiguredRecipient(): void $this->subject->notify($user, $this->request, 'TestTrigger', $configuration); } + #[WithTypo3ConfVars(['BE' => ['warning_email_addr' => 'global@example.com']])] public function testNotifyFallsBackToGlobalConfiguration(): void { $user = $this->createMockBackendUser(['uid' => 123]); $configuration = []; - $GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr'] = 'global@example.com'; - $fluidEmail = $this->createMock(FluidEmail::class); $fluidEmail->expects(self::once())->method('to')->with('global@example.com')->willReturnSelf(); $fluidEmail->expects(self::once())->method('setRequest')->willReturnSelf(); diff --git a/Tests/Unit/Security/LoginNotificationTest.php b/Tests/Unit/Security/LoginNotificationTest.php index 1ca0371..8d94a79 100644 --- a/Tests/Unit/Security/LoginNotificationTest.php +++ b/Tests/Unit/Security/LoginNotificationTest.php @@ -13,6 +13,7 @@ namespace MoveElevator\Typo3LoginWarning\Tests\Unit\Security; +use KonradMichalik\Ttt\Attribute\WithTypo3ConfVars; use MoveElevator\Typo3LoginWarning\Configuration; use MoveElevator\Typo3LoginWarning\Configuration\DetectorConfigurationBuilder; use MoveElevator\Typo3LoginWarning\Event\ModifyLoginNotificationEvent; @@ -33,6 +34,10 @@ * @author Konrad Michalik * @license GPL-2.0-or-later */ +#[WithTypo3ConfVars([ + 'EXTCONF' => [Configuration::EXT_KEY => ['_notification' => [], '_detector' => []]], + 'EXTENSIONS' => [Configuration::EXT_KEY => []], +])] final class LoginNotificationTest extends TestCase { private LoggerInterface&MockObject $logger; @@ -63,16 +68,6 @@ protected function setUp(): void $this->eventDispatcher, ); $this->subject->setLogger($this->logger); - - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][Configuration::EXT_KEY]['_notification'] = []; - $GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][Configuration::EXT_KEY]['_detector'] = []; - $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS'][Configuration::EXT_KEY] = []; - } - - protected function tearDown(): void - { - unset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF'][Configuration::EXT_KEY]); - unset($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS'][Configuration::EXT_KEY]); } public function testWarningAtLoginDoesNothingForNonBackendUsers(): void @@ -99,6 +94,11 @@ public function testWarningAtLoginDoesNothingWhenUserArrayIsNotArray(): void $this->addToAssertionCount(1); } + #[WithTypo3ConfVars(['EXTENSIONS' => [Configuration::EXT_KEY => [ + 'newIp' => ['active' => false], + 'longTimeNoSee' => ['active' => false], + 'outOfOffice' => ['active' => false], + ]]])] public function testWarningAtLoginHandlesNoActiveDetectors(): void { $user = $this->createMock(BackendUserAuthentication::class); @@ -106,12 +106,6 @@ public function testWarningAtLoginHandlesNoActiveDetectors(): void $request = $this->createMock(ServerRequestInterface::class); $event = new AfterUserLoggedInEvent($user, $request); - $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS'][Configuration::EXT_KEY] = [ - 'newIp' => ['active' => false], - 'longTimeNoSee' => ['active' => false], - 'outOfOffice' => ['active' => false], - ]; - ($this->subject)($event); // Should complete without errors when no detectors are active diff --git a/Tests/Unit/Utility/DeviceInfoParserTest.php b/Tests/Unit/Utility/DeviceInfoParserTest.php index d8af44b..463ac11 100644 --- a/Tests/Unit/Utility/DeviceInfoParserTest.php +++ b/Tests/Unit/Utility/DeviceInfoParserTest.php @@ -13,6 +13,7 @@ namespace MoveElevator\Typo3LoginWarning\Tests\Unit\Utility; +use KonradMichalik\Ttt\Attribute\WithTypo3ConfVars; use MoveElevator\Typo3LoginWarning\Utility\DeviceInfoParser; use PHPUnit\Framework\Attributes\{DataProvider, Test}; use PHPUnit\Framework\TestCase; @@ -258,11 +259,9 @@ public function parseOperatingSystemHandlesIosVersionFormat(): void } #[Test] + #[WithTypo3ConfVars(['SYS' => ['ddmmyy' => 'Y-m-d', 'hhmm' => 'H:i']])] public function parseFromRequestIncludesFormattedDate(): void { - $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] = 'Y-m-d'; - $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'] = 'H:i'; - $userAgent = 'Mozilla/5.0 (Test) AppleWebKit/537.36'; $request = $this->createMock(ServerRequestInterface::class); $request->method('getHeaderLine')->with('User-Agent')->willReturn($userAgent); diff --git a/composer.json b/composer.json index 8028fd8..44694d8 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,7 @@ }, "require-dev": { "eliashaeussler/version-bumper": "^2.4 || ^3.0 || ^4.0", + "konradmichalik/ttt": "^0.4.0", "mobiledetect/mobiledetectlib": "^4.11.0", "phpunit/phpcov": "^9.0 || ^10.0 || ^11.0 || ^13.0", "phpunit/phpunit": "^10.2 || ^11.0 || ^12.0 || ^13.0", diff --git a/composer.lock b/composer.lock index 7012e83..6472c87 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9d483e06e546120ee9375d585cdc723c", + "content-hash": "e59b6273bffdc7426b265e23a1f3085d", "packages": [ { "name": "bacon/bacon-qr-code", @@ -5568,6 +5568,73 @@ }, "time": "2026-06-04T05:37:13+00:00" }, + { + "name": "konradmichalik/ttt", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/konradmichalik/ttt.git", + "reference": "2b36b0ce42b7f980f0c23bc5f61a3da6e10cba8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/konradmichalik/ttt/zipball/2b36b0ce42b7f980f0c23bc5f61a3da6e10cba8d", + "reference": "2b36b0ce42b7f980f0c23bc5f61a3da6e10cba8d", + "shasum": "" + }, + "require": { + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "phpunit/phpunit": "^10.5 || ^11.0 || ^12.0 || ^13.0" + }, + "require-dev": { + "armin/editorconfig-cli": "^2.0", + "ergebnis/composer-normalize": "^2.44", + "konradmichalik/php-cs-fixer-preset": "^0.2.0", + "konradmichalik/php-doc-block-header-fixer": "^0.3.4", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "rector/rector": "^2.2", + "typo3/cms-core": "^13.4 || ^14.0", + "typo3/cms-frontend": "^13.4 || ^14.0" + }, + "suggest": { + "typo3/cms-core": "Required for TYPO3-specific attributes like InApplicationContext and WithEnvironment (^13.4 || ^14.0)", + "typo3/cms-frontend": "Required for WithFrontendUser (^13.4 || ^14.0)" + }, + "type": "library", + "autoload": { + "psr-4": { + "KonradMichalik\\Ttt\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-3.0-or-later" + ], + "authors": [ + { + "name": "Konrad Michalik", + "email": "hej@konradmichalik.dev", + "role": "Maintainer" + } + ], + "description": "ttt - TYPO3 Testing Terrarium. Declarative test sandboxing via PHP attributes: TYPO3_CONF_VARS, application context, environment and more - applied before the test, guaranteed to be restored afterwards.", + "keywords": [ + "Toolbox", + "attributes", + "php", + "phpunit", + "sandbox", + "testing", + "ttt", + "typo3" + ], + "support": { + "issues": "https://github.com/konradmichalik/ttt/issues", + "source": "https://github.com/konradmichalik/ttt/tree/0.4.0" + }, + "time": "2026-07-30T09:47:20+00:00" + }, { "name": "mobiledetect/mobiledetectlib", "version": "4.11.0", @@ -9800,5 +9867,5 @@ "platform-overrides": { "php": "8.2" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/phpunit.xml b/phpunit.xml index 82776b6..8c22281 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -7,6 +7,9 @@ bootstrap="vendor/autoload.php" colors="true" > + + +