From aec75f70ccd7338d2a47c284ad95c98c008744b0 Mon Sep 17 00:00:00 2001 From: Tormi Tabor Date: Thu, 9 Jul 2026 17:50:15 +0000 Subject: [PATCH 1/9] refactor(GH-470): Modernize AddClass with PHP 8.4 typing - Add declare(strict_types=1) and mark the class final - Type-hint add()'s parameters as mixed (rather than int|float) so non-numeric input still reaches the existing validity check and throws \InvalidArgumentException instead of a \TypeError - Declare the int|float return type explicitly --- .../custom/phpunit_example/src/AddClass.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/web/modules/custom/phpunit_example/src/AddClass.php b/web/modules/custom/phpunit_example/src/AddClass.php index c60481ad..3b7f2be5 100644 --- a/web/modules/custom/phpunit_example/src/AddClass.php +++ b/web/modules/custom/phpunit_example/src/AddClass.php @@ -1,5 +1,7 @@ Date: Thu, 9 Jul 2026 17:51:05 +0000 Subject: [PATCH 2/9] refactor(GH-470): Modernize AddClassTest to PHPUnit 11 attributes - Replace annotation-based metadata (@dataProvider, @group) with PHPUnit 11 attributes (#[DataProvider], #[Group], #[CoversClass]), placed before each method's docblock to satisfy WunderInlineComment - Add declare(strict_types=1) and void return types on test methods - Remove stale references to \PHPUnit_Framework_TestCase and setExpectedException(); update comments to describe the expectException() method actually used by the test - Fix assertEquals() argument order (expected, actual) in testAdd() --- .../tests/src/Unit/AddClassTest.php | 81 +++++++++---------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/web/modules/custom/phpunit_example/tests/src/Unit/AddClassTest.php b/web/modules/custom/phpunit_example/tests/src/Unit/AddClassTest.php index 264ac41d..a731a265 100644 --- a/web/modules/custom/phpunit_example/tests/src/Unit/AddClassTest.php +++ b/web/modules/custom/phpunit_example/tests/src/Unit/AddClassTest.php @@ -1,38 +1,43 @@ assertEquals($sut->add(2, 3), 5); + $this->assertEquals(5, $sut->add(2, 3)); } + #[DataProvider('addDataProvider')] /** * Test AddClass::add() with a data provider method. * - * This method is very similar to testAdd(), but uses a data provider method - * to test with a wider range of data. + * This method is very similar to testAdd(), but uses a data provider + * method to test with a wider range of data. * * You can tell PHPUnit which method is the data provider using the - * '@dataProvider' annotation. + * '#[DataProvider]' attribute. * * The data provider method just returns a big array of arrays of arguments. * That is, for each time you want this test method run, the data provider @@ -80,36 +86,29 @@ public function testAdd() { * tests 'good' data. When combined with testAddWithBadDataProvider(), * we get a better picture of the behavior of the method under test. * - * @dataProvider addDataProvider - * * @see self::addDataProvider() */ - public function testAddWithDataProvider($expected, $a, $b) { + public function testAddWithDataProvider($expected, $a, $b): void { $sut = new AddClass(); $this->assertEquals($expected, $sut->add($a, $b)); } + #[DataProvider('addBadDataProvider')] /** * Test AddClass::add() with data that should throw an exception. * * This method is similar to testAddWithDataProvider(), but the data * provider gives us data that should throw an exception. * - * This test uses the setExpectedException() method to tell PHPUnit that - * a thrown exception should pass the test. You specify a - * fully-qualified exception class name. If you specify \Exception, PHPUnit - * will pass any exception, whereas a more specific subclass of \Exception - * will require that exception type to be thrown. - * - * Alternately, you can use try and catch blocks with assertions in order - * to test exceptions. We won't demonstrate that here; it's a much better - * idea to test your exceptions with setExpectedException(). - * - * @dataProvider addBadDataProvider + * This test uses the expectException() method to tell PHPUnit that a + * thrown exception should pass the test. You specify a fully-qualified + * exception class name. If you specify \Exception, PHPUnit will pass any + * exception, whereas a more specific subclass of \Exception will require + * that exception type to be thrown. * * @see self::addBadDataProvider() */ - public function testAddWithBadDataProvider($a, $b) { + public function testAddWithBadDataProvider($a, $b): void { $sut = new AddClass(); $this->expectException(\InvalidArgumentException::class); $sut->add($a, $b); @@ -135,7 +134,7 @@ public function testAddWithBadDataProvider($a, $b) { * * @see self::testAddWithDataProvider() */ - public static function addDataProvider() { + public static function addDataProvider(): array { return [ [5, 2, 3], [50, 20, 30], @@ -154,7 +153,7 @@ public static function addDataProvider() { * * @see self::testAddWithBadDataProvider() */ - public static function addBadDataProvider() { + public static function addBadDataProvider(): array { $bad_data = []; // Set up an array with data that should cause add() // to throw an exception. From 24c693aec92a16938cb6ebde785d07011f6fbf41 Mon Sep 17 00:00:00 2001 From: Tormi Tabor Date: Thu, 9 Jul 2026 17:51:27 +0000 Subject: [PATCH 3/9] docs(GH-470): Update phpunit_example module docs to Drupal 11 Replace the outdated 'Drupal 8 unit testing' wording in the module file's doc block with 'Drupal 11 unit testing' to match the project's current core version requirement. --- web/modules/custom/phpunit_example/phpunit_example.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/modules/custom/phpunit_example/phpunit_example.module b/web/modules/custom/phpunit_example/phpunit_example.module index b02383de..aeeb7b02 100644 --- a/web/modules/custom/phpunit_example/phpunit_example.module +++ b/web/modules/custom/phpunit_example/phpunit_example.module @@ -9,7 +9,7 @@ * @defgroup phpunit_example Example: PHPUnit * @ingroup examples * @{ - * This example demonstrates PHPUnit for Drupal 8 unit testing. + * This example demonstrates PHPUnit for Drupal unit testing. */ /** From e981a9ba59c854e2d84da04195f40ee0f9936cd1 Mon Sep 17 00:00:00 2001 From: Tormi Tabor Date: Thu, 9 Jul 2026 17:51:42 +0000 Subject: [PATCH 4/9] chore(GH-470): Remove unused drupal:node dependency phpunit_example doesn't use Node API in its code, so the drupal:node dependency in phpunit_example.info.yml was unnecessary coupling. --- web/modules/custom/phpunit_example/phpunit_example.info.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web/modules/custom/phpunit_example/phpunit_example.info.yml b/web/modules/custom/phpunit_example/phpunit_example.info.yml index 4a9eea2d..52abee45 100644 --- a/web/modules/custom/phpunit_example/phpunit_example.info.yml +++ b/web/modules/custom/phpunit_example/phpunit_example.info.yml @@ -2,6 +2,4 @@ name: PHPUnit Example type: module description: Demonstrates how to use PHPUnit-based tests. package: Example modules -core_version_requirement: ^10 || ^11 -dependencies: - - drupal:node +core_version_requirement: ^11 From 702836a687a165b26cfc8e816f4873d94cd7fbe9 Mon Sep 17 00:00:00 2001 From: Tormi Tabor Date: Thu, 9 Jul 2026 17:52:05 +0000 Subject: [PATCH 5/9] chore(GH-470): Migrate phpunit.xml schema and fix coverage targets - Migrate the configuration to the PHPUnit 11.5 schema (drop the deprecated 9.3 block, HtmlOutputPrinter printerClass, and DrupalListener listener; add the required cacheDirectory attribute), removing the 'validates against a deprecated schema' warning - Point the include/exclude at web/modules/custom and web/themes/custom instead of web/core/*, so code coverage reports reflect this project's custom code rather than Drupal core --- phpunit.xml | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/phpunit.xml b/phpunit.xml index 796cbbc7..7500a113 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -49,19 +49,12 @@ - ./web/core/includes - ./web/core/lib - ./web/core/modules - ./web/core/modules - ./web/core/sites + ./web/modules/custom + ./web/themes/custom - ./web/core/modules/*/src/Tests - ./web/core/modules/*/tests - ./web/core/modules/*/src/Tests - ./web/core/modules/*/tests - ./web/core/modules/*/*/src/Tests - ./web/core/modules/*/*/tests + ./web/modules/custom/*/tests + ./web/themes/custom/*/tests From bb021e9bfbcbe798dca39dbfd98b39131c4add6f Mon Sep 17 00:00:00 2001 From: Tormi Tabor Date: Thu, 16 Jul 2026 23:26:12 +0300 Subject: [PATCH 6/9] fix(GH-470): Drop final on AddClass and type data-provider test params AddClass is a teaching example meant to be read and adapted, so remove the unexplained final modifier, which was also inconsistent with the rest of the custom codebase. Also add missing type declarations to the two data-provider-driven test methods: int|float for testAddWithDataProvider() (its data provider only supplies numeric values), and mixed for testAddWithBadDataProvider() (its data provider deliberately supplies non-numeric types). --- web/modules/custom/phpunit_example/src/AddClass.php | 2 +- .../custom/phpunit_example/tests/src/Unit/AddClassTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web/modules/custom/phpunit_example/src/AddClass.php b/web/modules/custom/phpunit_example/src/AddClass.php index 3b7f2be5..5443c79f 100644 --- a/web/modules/custom/phpunit_example/src/AddClass.php +++ b/web/modules/custom/phpunit_example/src/AddClass.php @@ -9,7 +9,7 @@ * * @ingroup phpunit_example */ -final class AddClass { +class AddClass { /** * A simple addition method with validity checking. diff --git a/web/modules/custom/phpunit_example/tests/src/Unit/AddClassTest.php b/web/modules/custom/phpunit_example/tests/src/Unit/AddClassTest.php index a731a265..c479af30 100644 --- a/web/modules/custom/phpunit_example/tests/src/Unit/AddClassTest.php +++ b/web/modules/custom/phpunit_example/tests/src/Unit/AddClassTest.php @@ -88,7 +88,7 @@ public function testAdd(): void { * * @see self::addDataProvider() */ - public function testAddWithDataProvider($expected, $a, $b): void { + public function testAddWithDataProvider(int|float $expected, int|float $a, int|float $b): void { $sut = new AddClass(); $this->assertEquals($expected, $sut->add($a, $b)); } @@ -108,7 +108,7 @@ public function testAddWithDataProvider($expected, $a, $b): void { * * @see self::addBadDataProvider() */ - public function testAddWithBadDataProvider($a, $b): void { + public function testAddWithBadDataProvider(mixed $a, mixed $b): void { $sut = new AddClass(); $this->expectException(\InvalidArgumentException::class); $sut->add($a, $b); From b99733d23fbe33049406a6cfdd59ce0ab6112c62 Mon Sep 17 00:00:00 2001 From: Tormi Tabor Date: Thu, 16 Jul 2026 23:27:01 +0300 Subject: [PATCH 7/9] chore(GH-470): Point wunderio/code-quality at PHPStan 2 upgrade branch Requires wunderio/code-quality:dev-GH-126 (wunderio/code-quality#127), which bumps mglaman/phpstan-drupal and phpstan/phpstan-deprecation-rules to their PHPStan-2-compatible releases. This resolves a false positive where PHPStan 1.12 rejected repeated #[Group(...)] attributes on a class even though PHPUnit\Framework\Attributes\Group is declared Attribute::IS_REPEATABLE. phpstan/phpstan and phpstan/phpstan-phpunit don't need to be pinned directly here; they resolve to their 2.x releases already via mglaman/phpstan-drupal's and drupal/core-dev's own constraints. Temporary until wunderio/code-quality cuts a tagged release including this upgrade (tracked in wunderio/code-quality#126), at which point this should switch back to a version constraint. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 79d2d6c9..93439c4a 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ }, "require-dev": { "drupal/core-dev": "^11.4", - "wunderio/code-quality": "^3.0" + "wunderio/code-quality": "dev-GH-126" }, "conflict": { "drupal/drupal": "*" From 48f5340f0f363c565f3186750a1fa491b50be408 Mon Sep 17 00:00:00 2001 From: Lauris Igaunis Date: Thu, 17 Sep 2026 14:51:28 +0300 Subject: [PATCH 8/9] chore(GH-470): Updated code quality version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 93439c4a..168b3455 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ }, "require-dev": { "drupal/core-dev": "^11.4", - "wunderio/code-quality": "dev-GH-126" + "wunderio/code-quality": "dev-GH-126-php" }, "conflict": { "drupal/drupal": "*" From 779eb1d3bcee9c5b9cc383cc547e1f2d4492d4a4 Mon Sep 17 00:00:00 2001 From: Lauris Igaunis Date: Thu, 17 Sep 2026 14:52:46 +0300 Subject: [PATCH 9/9] chore(GH-470): Sudo ln command --- .ddev/config.wunderio.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ddev/config.wunderio.yaml b/.ddev/config.wunderio.yaml index 6548d872..8d62501e 100644 --- a/.ddev/config.wunderio.yaml +++ b/.ddev/config.wunderio.yaml @@ -13,7 +13,7 @@ hooks: # @todo We could potentially make this work from recognizing the command. - exec: | if ! command -v wdr-core &> /dev/null; then - ln -s ${HOME}/wunderio/core/wdr-core.sh /usr/local/bin/wdr-core + sudo ln -s ${HOME}/wunderio/core/wdr-core.sh /usr/local/bin/wdr-core fi # Run once start hook if needed if [ ! -f "/mnt/wdr-hooks/ddev_web_post_start_once" ]; then