diff --git a/composer.json b/composer.json
index 9fef43ac90fa13a8451ead72677b295c0037df73..de31724f3e5322dc95e67f598760a9dde98a18db 100644
--- a/composer.json
+++ b/composer.json
@@ -33,13 +33,12 @@
         "phpstan/extension-installer": "^1.1",
         "phpstan/phpstan": "^1.10.62",
         "phpstan/phpstan-phpunit": "^1.3.16",
-        "phpunit/phpunit": "^9.6.13",
+        "phpunit/phpunit": "^10.5.19",
         "symfony/browser-kit": "^7.0",
         "symfony/css-selector": "^7.0",
         "symfony/dom-crawler": "^7.0",
         "symfony/error-handler": "^7.0",
         "symfony/lock": "^7.0",
-        "symfony/phpunit-bridge": "^7.0",
         "symfony/var-dumper": "^7.0"
     },
     "replace": {
diff --git a/composer.lock b/composer.lock
index 59cc6b18cd44ec5512126cb9745a0dcbb590dc84..a8ab3cc28454ab3e847c6bd387d30a6b10641101 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": "7033803d9382729f982fd06b4b8603de",
+    "content-hash": "0fb1643cd4e3341596fa89fcbdf1b7e4",
     "packages": [
         {
             "name": "asm89/stack-cors",
@@ -1861,29 +1861,29 @@
         },
         {
             "name": "sebastian/diff",
-            "version": "4.0.6",
+            "version": "5.1.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/diff.git",
-                "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
+                "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
-                "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
+                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e",
+                "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3",
-                "symfony/process": "^4.2 || ^5"
+                "phpunit/phpunit": "^10.0",
+                "symfony/process": "^6.4"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.0-dev"
+                    "dev-main": "5.1-dev"
                 }
             },
             "autoload": {
@@ -1915,7 +1915,8 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/diff/issues",
-                "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
+                "security": "https://github.com/sebastianbergmann/diff/security/policy",
+                "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1"
             },
             "funding": [
                 {
@@ -1923,7 +1924,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2024-03-02T06:30:58+00:00"
+            "time": "2024-03-02T07:15:17+00:00"
         },
         {
             "name": "symfony/console",
@@ -7160,16 +7161,16 @@
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "9.2.31",
+            "version": "10.1.14",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965"
+                "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965",
-                "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
+                "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
                 "shasum": ""
             },
             "require": {
@@ -7177,18 +7178,18 @@
                 "ext-libxml": "*",
                 "ext-xmlwriter": "*",
                 "nikic/php-parser": "^4.18 || ^5.0",
-                "php": ">=7.3",
-                "phpunit/php-file-iterator": "^3.0.3",
-                "phpunit/php-text-template": "^2.0.2",
-                "sebastian/code-unit-reverse-lookup": "^2.0.2",
-                "sebastian/complexity": "^2.0",
-                "sebastian/environment": "^5.1.2",
-                "sebastian/lines-of-code": "^1.0.3",
-                "sebastian/version": "^3.0.1",
+                "php": ">=8.1",
+                "phpunit/php-file-iterator": "^4.0",
+                "phpunit/php-text-template": "^3.0",
+                "sebastian/code-unit-reverse-lookup": "^3.0",
+                "sebastian/complexity": "^3.0",
+                "sebastian/environment": "^6.0",
+                "sebastian/lines-of-code": "^2.0",
+                "sebastian/version": "^4.0",
                 "theseer/tokenizer": "^1.2.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.1"
             },
             "suggest": {
                 "ext-pcov": "PHP extension that provides line coverage",
@@ -7197,7 +7198,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "9.2-dev"
+                    "dev-main": "10.1-dev"
                 }
             },
             "autoload": {
@@ -7226,7 +7227,7 @@
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
                 "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
-                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31"
+                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14"
             },
             "funding": [
                 {
@@ -7234,32 +7235,32 @@
                     "type": "github"
                 }
             ],
-            "time": "2024-03-02T06:37:42+00:00"
+            "time": "2024-03-12T15:33:41+00:00"
         },
         {
             "name": "phpunit/php-file-iterator",
-            "version": "3.0.6",
+            "version": "4.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
-                "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
+                "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
-                "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c",
+                "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-main": "4.0-dev"
                 }
             },
             "autoload": {
@@ -7286,7 +7287,8 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
-                "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
+                "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
+                "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0"
             },
             "funding": [
                 {
@@ -7294,28 +7296,28 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-12-02T12:48:52+00:00"
+            "time": "2023-08-31T06:24:48+00:00"
         },
         {
             "name": "phpunit/php-invoker",
-            "version": "3.1.1",
+            "version": "4.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-invoker.git",
-                "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
+                "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
-                "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
+                "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
                 "ext-pcntl": "*",
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "suggest": {
                 "ext-pcntl": "*"
@@ -7323,7 +7325,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-main": "4.0-dev"
                 }
             },
             "autoload": {
@@ -7349,7 +7351,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
-                "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
+                "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0"
             },
             "funding": [
                 {
@@ -7357,32 +7359,32 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-09-28T05:58:55+00:00"
+            "time": "2023-02-03T06:56:09+00:00"
         },
         {
             "name": "phpunit/php-text-template",
-            "version": "2.0.4",
+            "version": "3.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-text-template.git",
-                "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
+                "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
-                "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748",
+                "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-main": "3.0-dev"
                 }
             },
             "autoload": {
@@ -7408,7 +7410,8 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
-                "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
+                "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
+                "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1"
             },
             "funding": [
                 {
@@ -7416,32 +7419,32 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T05:33:50+00:00"
+            "time": "2023-08-31T14:07:24+00:00"
         },
         {
             "name": "phpunit/php-timer",
-            "version": "5.0.3",
+            "version": "6.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-timer.git",
-                "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
+                "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
-                "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d",
+                "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "5.0-dev"
+                    "dev-main": "6.0-dev"
                 }
             },
             "autoload": {
@@ -7467,7 +7470,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-timer/issues",
-                "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
+                "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0"
             },
             "funding": [
                 {
@@ -7475,24 +7478,23 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:16:10+00:00"
+            "time": "2023-02-03T06:57:52+00:00"
         },
         {
             "name": "phpunit/phpunit",
-            "version": "9.6.19",
+            "version": "10.5.20",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8"
+                "reference": "547d314dc24ec1e177720d45c6263fb226cc2ae3"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1a54a473501ef4cdeaae4e06891674114d79db8",
-                "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/547d314dc24ec1e177720d45c6263fb226cc2ae3",
+                "reference": "547d314dc24ec1e177720d45c6263fb226cc2ae3",
                 "shasum": ""
             },
             "require": {
-                "doctrine/instantiator": "^1.3.1 || ^2",
                 "ext-dom": "*",
                 "ext-json": "*",
                 "ext-libxml": "*",
@@ -7502,27 +7504,26 @@
                 "myclabs/deep-copy": "^1.10.1",
                 "phar-io/manifest": "^2.0.3",
                 "phar-io/version": "^3.0.2",
-                "php": ">=7.3",
-                "phpunit/php-code-coverage": "^9.2.28",
-                "phpunit/php-file-iterator": "^3.0.5",
-                "phpunit/php-invoker": "^3.1.1",
-                "phpunit/php-text-template": "^2.0.3",
-                "phpunit/php-timer": "^5.0.2",
-                "sebastian/cli-parser": "^1.0.1",
-                "sebastian/code-unit": "^1.0.6",
-                "sebastian/comparator": "^4.0.8",
-                "sebastian/diff": "^4.0.3",
-                "sebastian/environment": "^5.1.3",
-                "sebastian/exporter": "^4.0.5",
-                "sebastian/global-state": "^5.0.1",
-                "sebastian/object-enumerator": "^4.0.3",
-                "sebastian/resource-operations": "^3.0.3",
-                "sebastian/type": "^3.2",
-                "sebastian/version": "^3.0.2"
+                "php": ">=8.1",
+                "phpunit/php-code-coverage": "^10.1.5",
+                "phpunit/php-file-iterator": "^4.0",
+                "phpunit/php-invoker": "^4.0",
+                "phpunit/php-text-template": "^3.0",
+                "phpunit/php-timer": "^6.0",
+                "sebastian/cli-parser": "^2.0",
+                "sebastian/code-unit": "^2.0",
+                "sebastian/comparator": "^5.0",
+                "sebastian/diff": "^5.0",
+                "sebastian/environment": "^6.0",
+                "sebastian/exporter": "^5.1",
+                "sebastian/global-state": "^6.0.1",
+                "sebastian/object-enumerator": "^5.0",
+                "sebastian/recursion-context": "^5.0",
+                "sebastian/type": "^4.0",
+                "sebastian/version": "^4.0"
             },
             "suggest": {
-                "ext-soap": "To be able to generate mocks based on WSDL files",
-                "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
+                "ext-soap": "To be able to generate mocks based on WSDL files"
             },
             "bin": [
                 "phpunit"
@@ -7530,7 +7531,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "9.6-dev"
+                    "dev-main": "10.5-dev"
                 }
             },
             "autoload": {
@@ -7562,7 +7563,7 @@
             "support": {
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.19"
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.20"
             },
             "funding": [
                 {
@@ -7578,7 +7579,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-04-05T04:35:58+00:00"
+            "time": "2024-04-24T06:32:35+00:00"
         },
         {
             "name": "react/promise",
@@ -7655,28 +7656,28 @@
         },
         {
             "name": "sebastian/cli-parser",
-            "version": "1.0.2",
+            "version": "2.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/cli-parser.git",
-                "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
+                "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
-                "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
+                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084",
+                "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0-dev"
+                    "dev-main": "2.0-dev"
                 }
             },
             "autoload": {
@@ -7699,7 +7700,8 @@
             "homepage": "https://github.com/sebastianbergmann/cli-parser",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
-                "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
+                "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
+                "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1"
             },
             "funding": [
                 {
@@ -7707,32 +7709,32 @@
                     "type": "github"
                 }
             ],
-            "time": "2024-03-02T06:27:43+00:00"
+            "time": "2024-03-02T07:12:49+00:00"
         },
         {
             "name": "sebastian/code-unit",
-            "version": "1.0.8",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/code-unit.git",
-                "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
+                "reference": "a81fee9eef0b7a76af11d121767abc44c104e503"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
-                "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503",
+                "reference": "a81fee9eef0b7a76af11d121767abc44c104e503",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0-dev"
+                    "dev-main": "2.0-dev"
                 }
             },
             "autoload": {
@@ -7755,7 +7757,7 @@
             "homepage": "https://github.com/sebastianbergmann/code-unit",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/code-unit/issues",
-                "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
+                "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0"
             },
             "funding": [
                 {
@@ -7763,32 +7765,32 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:08:54+00:00"
+            "time": "2023-02-03T06:58:43+00:00"
         },
         {
             "name": "sebastian/code-unit-reverse-lookup",
-            "version": "2.0.3",
+            "version": "3.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
-                "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
+                "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
-                "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
+                "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-main": "3.0-dev"
                 }
             },
             "autoload": {
@@ -7810,7 +7812,7 @@
             "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
-                "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
+                "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0"
             },
             "funding": [
                 {
@@ -7818,34 +7820,36 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-09-28T05:30:19+00:00"
+            "time": "2023-02-03T06:59:15+00:00"
         },
         {
             "name": "sebastian/comparator",
-            "version": "4.0.8",
+            "version": "5.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/comparator.git",
-                "reference": "fa0f136dd2334583309d32b62544682ee972b51a"
+                "reference": "2db5010a484d53ebf536087a70b4a5423c102372"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
-                "reference": "fa0f136dd2334583309d32b62544682ee972b51a",
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372",
+                "reference": "2db5010a484d53ebf536087a70b4a5423c102372",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3",
-                "sebastian/diff": "^4.0",
-                "sebastian/exporter": "^4.0"
+                "ext-dom": "*",
+                "ext-mbstring": "*",
+                "php": ">=8.1",
+                "sebastian/diff": "^5.0",
+                "sebastian/exporter": "^5.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.3"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.0-dev"
+                    "dev-main": "5.0-dev"
                 }
             },
             "autoload": {
@@ -7884,7 +7888,8 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/comparator/issues",
-                "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
+                "security": "https://github.com/sebastianbergmann/comparator/security/policy",
+                "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1"
             },
             "funding": [
                 {
@@ -7892,33 +7897,33 @@
                     "type": "github"
                 }
             ],
-            "time": "2022-09-14T12:41:17+00:00"
+            "time": "2023-08-14T13:18:12+00:00"
         },
         {
             "name": "sebastian/complexity",
-            "version": "2.0.3",
+            "version": "3.2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/complexity.git",
-                "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
+                "reference": "68ff824baeae169ec9f2137158ee529584553799"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
-                "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
+                "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799",
+                "reference": "68ff824baeae169ec9f2137158ee529584553799",
                 "shasum": ""
             },
             "require": {
                 "nikic/php-parser": "^4.18 || ^5.0",
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-main": "3.2-dev"
                 }
             },
             "autoload": {
@@ -7941,7 +7946,8 @@
             "homepage": "https://github.com/sebastianbergmann/complexity",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/complexity/issues",
-                "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
+                "security": "https://github.com/sebastianbergmann/complexity/security/policy",
+                "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0"
             },
             "funding": [
                 {
@@ -7949,27 +7955,27 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-12-22T06:19:30+00:00"
+            "time": "2023-12-21T08:37:17+00:00"
         },
         {
             "name": "sebastian/environment",
-            "version": "5.1.5",
+            "version": "6.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/environment.git",
-                "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed"
+                "reference": "8074dbcd93529b357029f5cc5058fd3e43666984"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
-                "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
+                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984",
+                "reference": "8074dbcd93529b357029f5cc5058fd3e43666984",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "suggest": {
                 "ext-posix": "*"
@@ -7977,7 +7983,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "5.1-dev"
+                    "dev-main": "6.1-dev"
                 }
             },
             "autoload": {
@@ -7996,7 +8002,7 @@
                 }
             ],
             "description": "Provides functionality to handle HHVM/PHP environments",
-            "homepage": "http://www.github.com/sebastianbergmann/environment",
+            "homepage": "https://github.com/sebastianbergmann/environment",
             "keywords": [
                 "Xdebug",
                 "environment",
@@ -8004,7 +8010,8 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/environment/issues",
-                "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
+                "security": "https://github.com/sebastianbergmann/environment/security/policy",
+                "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0"
             },
             "funding": [
                 {
@@ -8012,34 +8019,34 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-02-03T06:03:51+00:00"
+            "time": "2024-03-23T08:47:14+00:00"
         },
         {
             "name": "sebastian/exporter",
-            "version": "4.0.6",
+            "version": "5.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
+                "reference": "955288482d97c19a372d3f31006ab3f37da47adf"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
-                "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf",
+                "reference": "955288482d97c19a372d3f31006ab3f37da47adf",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3",
-                "sebastian/recursion-context": "^4.0"
+                "ext-mbstring": "*",
+                "php": ">=8.1",
+                "sebastian/recursion-context": "^5.0"
             },
             "require-dev": {
-                "ext-mbstring": "*",
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.0-dev"
+                    "dev-main": "5.1-dev"
                 }
             },
             "autoload": {
@@ -8081,7 +8088,8 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/exporter/issues",
-                "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
+                "security": "https://github.com/sebastianbergmann/exporter/security/policy",
+                "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2"
             },
             "funding": [
                 {
@@ -8089,38 +8097,35 @@
                     "type": "github"
                 }
             ],
-            "time": "2024-03-02T06:33:00+00:00"
+            "time": "2024-03-02T07:17:12+00:00"
         },
         {
             "name": "sebastian/global-state",
-            "version": "5.0.7",
+            "version": "6.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
+                "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
-                "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
+                "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3",
-                "sebastian/object-reflector": "^2.0",
-                "sebastian/recursion-context": "^4.0"
+                "php": ">=8.1",
+                "sebastian/object-reflector": "^3.0",
+                "sebastian/recursion-context": "^5.0"
             },
             "require-dev": {
                 "ext-dom": "*",
-                "phpunit/phpunit": "^9.3"
-            },
-            "suggest": {
-                "ext-uopz": "*"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "5.0-dev"
+                    "dev-main": "6.0-dev"
                 }
             },
             "autoload": {
@@ -8139,13 +8144,14 @@
                 }
             ],
             "description": "Snapshotting of global state",
-            "homepage": "http://www.github.com/sebastianbergmann/global-state",
+            "homepage": "https://www.github.com/sebastianbergmann/global-state",
             "keywords": [
                 "global state"
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/global-state/issues",
-                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
+                "security": "https://github.com/sebastianbergmann/global-state/security/policy",
+                "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2"
             },
             "funding": [
                 {
@@ -8153,33 +8159,33 @@
                     "type": "github"
                 }
             ],
-            "time": "2024-03-02T06:35:11+00:00"
+            "time": "2024-03-02T07:19:19+00:00"
         },
         {
             "name": "sebastian/lines-of-code",
-            "version": "1.0.4",
+            "version": "2.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/lines-of-code.git",
-                "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
+                "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
-                "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
+                "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0",
+                "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0",
                 "shasum": ""
             },
             "require": {
                 "nikic/php-parser": "^4.18 || ^5.0",
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0-dev"
+                    "dev-main": "2.0-dev"
                 }
             },
             "autoload": {
@@ -8202,7 +8208,8 @@
             "homepage": "https://github.com/sebastianbergmann/lines-of-code",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
-                "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
+                "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
+                "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2"
             },
             "funding": [
                 {
@@ -8210,34 +8217,34 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-12-22T06:20:34+00:00"
+            "time": "2023-12-21T08:38:20+00:00"
         },
         {
             "name": "sebastian/object-enumerator",
-            "version": "4.0.4",
+            "version": "5.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/object-enumerator.git",
-                "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
+                "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
-                "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906",
+                "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3",
-                "sebastian/object-reflector": "^2.0",
-                "sebastian/recursion-context": "^4.0"
+                "php": ">=8.1",
+                "sebastian/object-reflector": "^3.0",
+                "sebastian/recursion-context": "^5.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.0-dev"
+                    "dev-main": "5.0-dev"
                 }
             },
             "autoload": {
@@ -8259,7 +8266,7 @@
             "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
-                "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
+                "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0"
             },
             "funding": [
                 {
@@ -8267,32 +8274,32 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:12:34+00:00"
+            "time": "2023-02-03T07:08:32+00:00"
         },
         {
             "name": "sebastian/object-reflector",
-            "version": "2.0.4",
+            "version": "3.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/object-reflector.git",
-                "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
+                "reference": "24ed13d98130f0e7122df55d06c5c4942a577957"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
-                "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957",
+                "reference": "24ed13d98130f0e7122df55d06c5c4942a577957",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-main": "3.0-dev"
                 }
             },
             "autoload": {
@@ -8314,7 +8321,7 @@
             "homepage": "https://github.com/sebastianbergmann/object-reflector/",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
-                "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
+                "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0"
             },
             "funding": [
                 {
@@ -8322,32 +8329,32 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:14:26+00:00"
+            "time": "2023-02-03T07:06:18+00:00"
         },
         {
             "name": "sebastian/recursion-context",
-            "version": "4.0.5",
+            "version": "5.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/recursion-context.git",
-                "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
+                "reference": "05909fb5bc7df4c52992396d0116aed689f93712"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
-                "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
+                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712",
+                "reference": "05909fb5bc7df4c52992396d0116aed689f93712",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.0-dev"
+                    "dev-main": "5.0-dev"
                 }
             },
             "autoload": {
@@ -8377,7 +8384,7 @@
             "homepage": "https://github.com/sebastianbergmann/recursion-context",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
-                "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
+                "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0"
             },
             "funding": [
                 {
@@ -8385,86 +8392,32 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-02-03T06:07:39+00:00"
-        },
-        {
-            "name": "sebastian/resource-operations",
-            "version": "3.0.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/resource-operations.git",
-                "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
-                "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=7.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^9.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-main": "3.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Provides a list of PHP built-in functions that operate on resources",
-            "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
-            "support": {
-                "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
-            },
-            "funding": [
-                {
-                    "url": "https://github.com/sebastianbergmann",
-                    "type": "github"
-                }
-            ],
-            "time": "2024-03-14T16:00:52+00:00"
+            "time": "2023-02-03T07:05:40+00:00"
         },
         {
             "name": "sebastian/type",
-            "version": "3.2.1",
+            "version": "4.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/type.git",
-                "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7"
+                "reference": "462699a16464c3944eefc02ebdd77882bd3925bf"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
-                "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
+                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf",
+                "reference": "462699a16464c3944eefc02ebdd77882bd3925bf",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.5"
+                "phpunit/phpunit": "^10.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.2-dev"
+                    "dev-main": "4.0-dev"
                 }
             },
             "autoload": {
@@ -8487,7 +8440,7 @@
             "homepage": "https://github.com/sebastianbergmann/type",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/type/issues",
-                "source": "https://github.com/sebastianbergmann/type/tree/3.2.1"
+                "source": "https://github.com/sebastianbergmann/type/tree/4.0.0"
             },
             "funding": [
                 {
@@ -8495,29 +8448,29 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-02-03T06:13:03+00:00"
+            "time": "2023-02-03T07:10:45+00:00"
         },
         {
             "name": "sebastian/version",
-            "version": "3.0.2",
+            "version": "4.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/version.git",
-                "reference": "c6c1022351a901512170118436c764e473f6de8c"
+                "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
-                "reference": "c6c1022351a901512170118436c764e473f6de8c",
+                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17",
+                "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.1"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-main": "4.0-dev"
                 }
             },
             "autoload": {
@@ -8540,7 +8493,7 @@
             "homepage": "https://github.com/sebastianbergmann/version",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/version/issues",
-                "source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
+                "source": "https://github.com/sebastianbergmann/version/tree/4.0.1"
             },
             "funding": [
                 {
@@ -8548,7 +8501,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-09-28T06:39:44+00:00"
+            "time": "2023-02-07T11:34:05+00:00"
         },
         {
             "name": "seld/jsonlint",
@@ -9204,87 +9157,6 @@
             ],
             "time": "2024-03-19T09:26:35+00:00"
         },
-        {
-            "name": "symfony/phpunit-bridge",
-            "version": "v7.0.6",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/phpunit-bridge.git",
-                "reference": "a014167aa1f66cb9990675840da65609d3e61612"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/a014167aa1f66cb9990675840da65609d3e61612",
-                "reference": "a014167aa1f66cb9990675840da65609d3e61612",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=7.2.5"
-            },
-            "conflict": {
-                "phpunit/phpunit": "<7.5|9.1.2"
-            },
-            "require-dev": {
-                "symfony/deprecation-contracts": "^2.5|^3.0",
-                "symfony/error-handler": "^5.4|^6.4|^7.0",
-                "symfony/polyfill-php81": "^1.27"
-            },
-            "bin": [
-                "bin/simple-phpunit"
-            ],
-            "type": "symfony-bridge",
-            "extra": {
-                "thanks": {
-                    "name": "phpunit/phpunit",
-                    "url": "https://github.com/sebastianbergmann/phpunit"
-                }
-            },
-            "autoload": {
-                "files": [
-                    "bootstrap.php"
-                ],
-                "psr-4": {
-                    "Symfony\\Bridge\\PhpUnit\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Provides utilities for PHPUnit, especially user deprecation notices management",
-            "homepage": "https://symfony.com",
-            "support": {
-                "source": "https://github.com/symfony/phpunit-bridge/tree/v7.0.6"
-            },
-            "funding": [
-                {
-                    "url": "https://symfony.com/sponsor",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/fabpot",
-                    "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2024-03-19T11:57:22+00:00"
-        },
         {
             "name": "theseer/tokenizer",
             "version": "1.2.3",
diff --git a/composer/Metapackage/CoreRecommended/composer.json b/composer/Metapackage/CoreRecommended/composer.json
index 79ba852d5cd5252ca50bf99de3bb4ab523a5c281..9095f5a62eaf877418d3132e2c5b9313c41132db 100644
--- a/composer/Metapackage/CoreRecommended/composer.json
+++ b/composer/Metapackage/CoreRecommended/composer.json
@@ -30,7 +30,7 @@
         "psr/http-factory": "~1.0.2",
         "psr/log": "~3.0.0",
         "ralouphie/getallheaders": "~3.0.3",
-        "sebastian/diff": "~4.0.6",
+        "sebastian/diff": "~5.1.1",
         "symfony/console": "~v7.0.6",
         "symfony/dependency-injection": "~v7.0.6",
         "symfony/deprecation-contracts": "~v3.4.0",
diff --git a/composer/Metapackage/DevDependencies/composer.json b/composer/Metapackage/DevDependencies/composer.json
index 396fbfad68e5049081118102b165213ea800335b..259f200cec6b035f6e5a522e45f29912437aaa66 100644
--- a/composer/Metapackage/DevDependencies/composer.json
+++ b/composer/Metapackage/DevDependencies/composer.json
@@ -25,13 +25,12 @@
         "phpstan/extension-installer": "^1.1",
         "phpstan/phpstan": "^1.10.62",
         "phpstan/phpstan-phpunit": "^1.3.16",
-        "phpunit/phpunit": "^9.6.13",
+        "phpunit/phpunit": "^10.5.19",
         "symfony/browser-kit": "^7.0",
         "symfony/css-selector": "^7.0",
         "symfony/dom-crawler": "^7.0",
         "symfony/error-handler": "^7.0",
         "symfony/lock": "^7.0",
-        "symfony/phpunit-bridge": "^7.0",
         "symfony/var-dumper": "^7.0"
     }
 }
diff --git a/composer/Metapackage/PinnedDevDependencies/composer.json b/composer/Metapackage/PinnedDevDependencies/composer.json
index c430ac3a3dcf4e2b02c46015aae26b78176c6f7a..e8bc1a5953d2b6149234beda245ff277fc78c55b 100644
--- a/composer/Metapackage/PinnedDevDependencies/composer.json
+++ b/composer/Metapackage/PinnedDevDependencies/composer.json
@@ -52,28 +52,27 @@
         "phpstan/phpstan": "1.10.66",
         "phpstan/phpstan-deprecation-rules": "1.1.4",
         "phpstan/phpstan-phpunit": "1.3.16",
-        "phpunit/php-code-coverage": "9.2.31",
-        "phpunit/php-file-iterator": "3.0.6",
-        "phpunit/php-invoker": "3.1.1",
-        "phpunit/php-text-template": "2.0.4",
-        "phpunit/php-timer": "5.0.3",
-        "phpunit/phpunit": "9.6.19",
+        "phpunit/php-code-coverage": "10.1.14",
+        "phpunit/php-file-iterator": "4.1.0",
+        "phpunit/php-invoker": "4.0.0",
+        "phpunit/php-text-template": "3.0.1",
+        "phpunit/php-timer": "6.0.0",
+        "phpunit/phpunit": "10.5.20",
         "react/promise": "v3.1.0",
-        "sebastian/cli-parser": "1.0.2",
-        "sebastian/code-unit": "1.0.8",
-        "sebastian/code-unit-reverse-lookup": "2.0.3",
-        "sebastian/comparator": "4.0.8",
-        "sebastian/complexity": "2.0.3",
-        "sebastian/environment": "5.1.5",
-        "sebastian/exporter": "4.0.6",
-        "sebastian/global-state": "5.0.7",
-        "sebastian/lines-of-code": "1.0.4",
-        "sebastian/object-enumerator": "4.0.4",
-        "sebastian/object-reflector": "2.0.4",
-        "sebastian/recursion-context": "4.0.5",
-        "sebastian/resource-operations": "3.0.4",
-        "sebastian/type": "3.2.1",
-        "sebastian/version": "3.0.2",
+        "sebastian/cli-parser": "2.0.1",
+        "sebastian/code-unit": "2.0.0",
+        "sebastian/code-unit-reverse-lookup": "3.0.0",
+        "sebastian/comparator": "5.0.1",
+        "sebastian/complexity": "3.2.0",
+        "sebastian/environment": "6.1.0",
+        "sebastian/exporter": "5.1.2",
+        "sebastian/global-state": "6.0.2",
+        "sebastian/lines-of-code": "2.0.2",
+        "sebastian/object-enumerator": "5.0.0",
+        "sebastian/object-reflector": "3.0.0",
+        "sebastian/recursion-context": "5.0.0",
+        "sebastian/type": "4.0.0",
+        "sebastian/version": "4.0.1",
         "seld/jsonlint": "1.10.2",
         "seld/phar-utils": "1.2.1",
         "seld/signal-handler": "2.0.2",
@@ -84,7 +83,6 @@
         "symfony/css-selector": "v7.0.3",
         "symfony/dom-crawler": "v7.0.4",
         "symfony/lock": "v7.0.6",
-        "symfony/phpunit-bridge": "v7.0.6",
         "theseer/tokenizer": "1.2.3",
         "webflo/drupal-finder": "1.2.2",
         "webmozart/assert": "1.11.0"
diff --git a/composer/Plugin/VendorHardening/Config.php b/composer/Plugin/VendorHardening/Config.php
index 3db5c3372a3b0338c7ab19d26172726adc64dfd9..411425b14f539ee6c8960a16c73adefceb6793af 100644
--- a/composer/Plugin/VendorHardening/Config.php
+++ b/composer/Plugin/VendorHardening/Config.php
@@ -70,7 +70,6 @@ class Config {
     'symfony/event-dispatcher' => ['Tests'],
     'symfony/http-foundation' => ['Tests'],
     'symfony/http-kernel' => ['Tests'],
-    'symfony/phpunit-bridge' => ['Tests'],
     'symfony/process' => ['Tests'],
     'symfony/psr-http-message-bridge' => ['Tests'],
     'symfony/routing' => ['Tests'],
diff --git a/core/.deprecation-ignore.txt b/core/.deprecation-ignore.txt
index 92d3da6177c9b789129312147ff952e7ae2c7916..ec42944605b3e2778bd2c50b4201068edebac09b 100644
--- a/core/.deprecation-ignore.txt
+++ b/core/.deprecation-ignore.txt
@@ -3,7 +3,6 @@
 # See https://www.drupal.org/node/3285162 for more details.
 
 %The "Symfony\\Component\\Validator\\Context\\ExecutionContextInterface::.*\(\)" method is considered internal Used by the validator engine\. (Should not be called by user\W+code\. )?It may change without further notice\. You should not extend it from "[^"]+"\.%
-%The "PHPUnit\\Framework\\TestCase::addWarning\(\)" method is considered internal%
 
 # Skip some dependencies' DebugClassLoader forward compatibility warnings.
 %Method "Behat\\[^"]+" might add "[^"]+" as a native return type declaration in the future. Do the same in (child class|implementation) "[^"]+" now to avoid errors or add an explicit @return annotation to suppress this message%
@@ -17,16 +16,13 @@
 %Method "Twig\\TokenParser\\TokenParserInterface::[^"]+" might add "[^"]+" as a native return type declaration in the future. Do the same in (child class|implementation) "[^"]+" now to avoid errors or add an explicit @return annotation to suppress this message%
 %Method "WebDriver\\Service\\CurlServiceInterface::[^"]+" might add "[^"]+" as a native return type declaration in the future. Do the same in implementation "[^"]+" now to avoid errors or add an explicit @return annotation to suppress this message%
 
+# Indirect deprecations. These are not in Drupal's remit to fix, but it is
+# worth keeping track of dependencies' issues.
+%Method "[^"]+" might add "[^"]+" as a native return type declaration in the future. Do the same in implementation "org\\bovigo\\vfs\\[^"]+" now to avoid errors or add an explicit @return annotation to suppress this message%
+
 # The following deprecation is listed for Twig 2 compatibility when unit
 # testing using \Symfony\Component\ErrorHandler\DebugClassLoader.
 %The "Twig\\Environment::getTemplateClass\(\)" method is considered internal\. It may change without further notice\. You should not extend it from "Drupal\\Core\\Template\\TwigEnvironment"\.%
 
-# PHPUnit 9.
-%"PHPUnit\\Framework\\TestListener".*is deprecated%
-%"PHPUnit\\Framework\\TestListenerDefaultImplementation".*is deprecated%
-%"PHPUnit\\Framework\\TestSuite".*is considered internal%
-%"PHPUnit\\TextUI\\DefaultResultPrinter".*is considered internal%
-
-# PHPUnit 9.6.
-%Expecting E_WARNING and E_USER_WARNING is deprecated and will no longer be possible in PHPUnit 10%
-%Expecting E_ERROR and E_USER_ERROR is deprecated and will no longer be possible in PHPUnit 10%
+# PHPUnit 10.
+%The "PHPUnit\\Framework\\TestCase::__construct\(\)" method is considered internal.*You should not extend it from "Drupal\\[^"]+"%
diff --git a/core/.phpstan-baseline.php b/core/.phpstan-baseline.php
index ab6639d657d25052679a34a97ca0762e3f575a8d..609ee106deb5b100d42f5e8ddbd105bc84180c44 100644
--- a/core/.phpstan-baseline.php
+++ b/core/.phpstan-baseline.php
@@ -841,6 +841,11 @@
 	'count' => 1,
 	'path' => __DIR__ . '/modules/filter/src/Plugin/Filter/FilterHtml.php',
 ];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/modules/help/tests/src/Unit/HelpTopicTwigTest.php',
+];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\history\\\\Plugin\\\\views\\\\field\\\\HistoryUserTimestamp\\:\\:render\\(\\) should return Drupal\\\\Component\\\\Render\\\\MarkupInterface\\|string but return statement is missing\\.$#',
 	'count' => 1,
@@ -1106,6 +1111,11 @@
 	'count' => 1,
 	'path' => __DIR__ . '/modules/migrate/tests/src/Kernel/MigrateTestBase.php',
 ];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/modules/migrate/tests/src/Unit/MigrateExecutableTest.php',
+];
 $ignoreErrors[] = [
 	'message' => '#^Variable \\$sub_process_plugins might not be defined\\.$#',
 	'count' => 2,
@@ -1356,6 +1366,11 @@
 	'count' => 1,
 	'path' => __DIR__ . '/modules/serialization/src/Normalizer/EntityNormalizer.php',
 ];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/modules/serialization/tests/src/Unit/Normalizer/NormalizerBaseTest.php',
+];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\shortcut\\\\Form\\\\SetCustomize\\:\\:save\\(\\) should return int but return statement is missing\\.$#',
 	'count' => 1,
@@ -1838,6 +1853,36 @@
 	'count' => 2,
 	'path' => __DIR__ . '/modules/views/tests/src/Kernel/Plugin/StyleTest.php',
 ];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 5,
+	'path' => __DIR__ . '/modules/views/tests/src/Unit/Plugin/Derivative/ViewsLocalTaskTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 2,
+	'path' => __DIR__ . '/modules/views/tests/src/Unit/Plugin/argument_validator/EntityTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/modules/views/tests/src/Unit/Plugin/display/PathPluginBaseTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/modules/views/tests/src/Unit/Plugin/pager/PagerPluginBaseTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/modules/views/tests/src/Unit/Plugin/pager/SqlBaseTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/modules/views/tests/src/Unit/Plugin/views/field/EntityOperationsUnitTest.php',
+];
 $ignoreErrors[] = [
 	'message' => '#^Variable \\$relationship_handler in empty\\(\\) always exists and is not falsy\\.$#',
 	'count' => 1,
@@ -1963,6 +2008,11 @@
 	'count' => 1,
 	'path' => __DIR__ . '/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php',
 ];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 2,
+	'path' => __DIR__ . '/tests/Drupal/BuildTests/Framework/Tests/BuildTestTest.php',
+];
 $ignoreErrors[] = [
 	'message' => '#^Variable \\$found might not be defined\\.$#',
 	'count' => 1,
@@ -1993,6 +2043,16 @@
 	'count' => 1,
 	'path' => __DIR__ . '/tests/Drupal/KernelTests/Core/Entity/FieldableEntityDefinitionUpdateTest.php',
 ];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 2,
+	'path' => __DIR__ . '/tests/Drupal/KernelTests/Core/Installer/InstallerRedirectTraitTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/tests/Drupal/KernelTests/Core/Installer/InstallerRedirectTraitTest.php',
+];
 $ignoreErrors[] = [
 	'message' => '#^Variable \\$value in isset\\(\\) always exists and is not nullable\\.$#',
 	'count' => 1,
@@ -2074,6 +2134,16 @@
 	'count' => 1,
 	'path' => __DIR__ . '/tests/Drupal/Tests/Component/Plugin/Factory/ReflectionFactoryTest.php',
 ];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 4,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Component/Plugin/PluginBaseTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 2,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Component/Plugin/PluginManagerBaseTest.php',
+];
 $ignoreErrors[] = [
 	'message' => '#^Missing cache backend declaration for performance\\.$#',
 	'count' => 1,
@@ -2084,6 +2154,51 @@
 	'count' => 1,
 	'path' => __DIR__ . '/tests/Drupal/Tests/Composer/ComposerTest.php',
 ];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Controller/ControllerBaseTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityFormTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityLinkTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 2,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityStorageBaseTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 2,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityTypeManagerTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityTypeTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php',
+];
 $ignoreErrors[] = [
 	'message' => '#^Trying to mock an undefined method getRevisionId\\(\\) on class Drupal\\\\Tests\\\\Core\\\\Entity\\\\UrlTestEntity\\.$#',
 	'count' => 1,
@@ -2094,12 +2209,27 @@
 	'count' => 1,
 	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php',
 ];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php',
+];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\MockObject\\\\MockBuilder\\.$#',
+	'count' => 3,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageTest.php',
+];
 $ignoreErrors[] = [
 	'message' => '#^Call to deprecated method getConfig\\(\\) of class GuzzleHttp\\\\Client\\:
 Client\\:\\:getConfig will be removed in guzzlehttp/guzzle\\:8\\.0\\.$#',
 	'count' => 1,
 	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Http/ClientFactoryTest.php',
 ];
+$ignoreErrors[] = [
+	'message' => '#^Call to deprecated method getMockForAbstractClass\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#',
+	'count' => 1,
+	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Lock/LockBackendAbstractTest.php',
+];
 $ignoreErrors[] = [
 	'message' => '#^Call to method getDefinitions\\(\\) on an unknown class Drupal\\\\Core\\\\Plugin\\\\CategorizingPluginManagerTrait\\.$#',
 	'count' => 1,
@@ -2146,51 +2276,5 @@
 	'count' => 1,
 	'path' => __DIR__ . '/tests/Drupal/Tests/DrupalTestBrowser.php',
 ];
-$ignoreErrors[] = [
-	'message' => '#^Class Drupal\\\\Tests\\\\Listeners\\\\DrupalListener implements deprecated interface PHPUnit\\\\Framework\\\\TestListener\\.$#',
-	'count' => 1,
-	'path' => __DIR__ . '/tests/Drupal/Tests/Listeners/DrupalListener.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Usage of deprecated trait PHPUnit\\\\Framework\\\\TestListenerDefaultImplementation in class Drupal\\\\Tests\\\\Listeners\\\\DrupalListener\\:
-The `TestListener` interface is deprecated$#',
-	'count' => 1,
-	'path' => __DIR__ . '/tests/Drupal/Tests/Listeners/DrupalListener.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Class Drupal\\\\Tests\\\\TestSuites\\\\BuildTestSuite extends deprecated class Drupal\\\\Tests\\\\TestSuites\\\\TestSuiteBase\\:
-in drupal\\:10\\.3\\.0 and is removed from drupal\\:11\\.0\\.0\\. There is no
-  replacement and test discovery will be handled differently in PHPUnit 10\\.$#',
-	'count' => 1,
-	'path' => __DIR__ . '/tests/TestSuites/BuildTestSuite.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Class Drupal\\\\Tests\\\\TestSuites\\\\FunctionalJavascriptTestSuite extends deprecated class Drupal\\\\Tests\\\\TestSuites\\\\TestSuiteBase\\:
-in drupal\\:10\\.3\\.0 and is removed from drupal\\:11\\.0\\.0\\. There is no
-  replacement and test discovery will be handled differently in PHPUnit 10\\.$#',
-	'count' => 1,
-	'path' => __DIR__ . '/tests/TestSuites/FunctionalJavascriptTestSuite.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Class Drupal\\\\Tests\\\\TestSuites\\\\FunctionalTestSuite extends deprecated class Drupal\\\\Tests\\\\TestSuites\\\\TestSuiteBase\\:
-in drupal\\:10\\.3\\.0 and is removed from drupal\\:11\\.0\\.0\\. There is no
-  replacement and test discovery will be handled differently in PHPUnit 10\\.$#',
-	'count' => 1,
-	'path' => __DIR__ . '/tests/TestSuites/FunctionalTestSuite.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Class Drupal\\\\Tests\\\\TestSuites\\\\KernelTestSuite extends deprecated class Drupal\\\\Tests\\\\TestSuites\\\\TestSuiteBase\\:
-in drupal\\:10\\.3\\.0 and is removed from drupal\\:11\\.0\\.0\\. There is no
-  replacement and test discovery will be handled differently in PHPUnit 10\\.$#',
-	'count' => 1,
-	'path' => __DIR__ . '/tests/TestSuites/KernelTestSuite.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Class Drupal\\\\Tests\\\\TestSuites\\\\UnitTestSuite extends deprecated class Drupal\\\\Tests\\\\TestSuites\\\\TestSuiteBase\\:
-in drupal\\:10\\.3\\.0 and is removed from drupal\\:11\\.0\\.0\\. There is no
-  replacement and test discovery will be handled differently in PHPUnit 10\\.$#',
-	'count' => 1,
-	'path' => __DIR__ . '/tests/TestSuites/UnitTestSuite.php',
-];
 
 return ['parameters' => ['ignoreErrors' => $ignoreErrors]];
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index cf632ae733742ff8aa4ff76cecf7d6ee38fdc328..881d695b4aeee7009cf360380a2c8de5cf12b1fd 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -218,6 +218,9 @@ function drupal_valid_test_ua($new_prefix = NULL) {
 
 /**
  * Generates a user agent string with a HMAC and timestamp for tests.
+ *
+ * @return string|null
+ *   The user agent, or NULL on failure.
  */
 function drupal_generate_test_ua($prefix) {
   static $key, $last_prefix;
@@ -242,7 +245,9 @@ function drupal_generate_test_ua($prefix) {
       // Generate and save a new hash salt for a test run.
       // Consumed by drupal_valid_test_ua() before settings.php is loaded.
       $private_key = Crypt::randomBytesBase64(55);
-      file_put_contents($key_file, $private_key);
+      if (!@file_put_contents($key_file, $private_key)) {
+        return NULL;
+      }
     }
     // The file properties add more entropy not easily accessible to others.
     $key = $private_key . filectime(__FILE__) . fileinode(__FILE__);
diff --git a/core/lib/Drupal/Core/Database/Database.php b/core/lib/Drupal/Core/Database/Database.php
index 4e87201fba8824d780c4eb1ad5f87c986cd04834..aceb5fd128273f0b95e028cabbb11499f4084bfd 100644
--- a/core/lib/Drupal/Core/Database/Database.php
+++ b/core/lib/Drupal/Core/Database/Database.php
@@ -457,6 +457,13 @@ public static function closeConnection($target = NULL, $key = NULL) {
       }
       unset(self::$connections[$key]);
     }
+
+    // When last connection for $key is closed, we also stop any active
+    // logging.
+    if (empty(self::$connections[$key])) {
+      unset(self::$logs[$key]);
+    }
+
     // Force garbage collection to run. This ensures that client connection
     // objects and results in the connection being closed are destroyed.
     gc_collect_cycles();
diff --git a/core/lib/Drupal/Core/Test/HttpClientMiddleware/TestHttpClientMiddleware.php b/core/lib/Drupal/Core/Test/HttpClientMiddleware/TestHttpClientMiddleware.php
index 4fbfff01cdd0f552a7184e550cc56e0d7df8e468..b0e950868f7c24bf98e3a04605538b92119f2d05 100644
--- a/core/lib/Drupal/Core/Test/HttpClientMiddleware/TestHttpClientMiddleware.php
+++ b/core/lib/Drupal/Core/Test/HttpClientMiddleware/TestHttpClientMiddleware.php
@@ -23,8 +23,8 @@ public function __invoke() {
     // database prefix were stored statically in a file or database variable.
     return function ($handler) {
       return function (RequestInterface $request, array $options) use ($handler) {
-        if ($test_prefix = drupal_valid_test_ua()) {
-          $request = $request->withHeader('User-Agent', drupal_generate_test_ua($test_prefix));
+        if ($user_agent = drupal_generate_test_ua(drupal_valid_test_ua())) {
+          $request = $request->withHeader('User-Agent', $user_agent);
         }
         return $handler($request, $options)
           ->then(function (ResponseInterface $response) {
@@ -47,7 +47,7 @@ public function __invoke() {
                     if ($parameters[1] === 'User deprecated function') {
                       // Fire the same deprecation message to allow it to be
                       // collected by
-                      // \Symfony\Bridge\PhpUnit\DeprecationErrorHandler::collectDeprecations().
+                      // \Drupal\TestTools\Extension\DeprecationBridge\DeprecationHandler::collectActualDeprecation().
                       // phpcs:ignore Drupal.Semantics.FunctionTriggerError
                       @trigger_error((string) $parameters[0], E_USER_DEPRECATED);
                     }
diff --git a/core/lib/Drupal/Core/Test/PhpUnitTestRunner.php b/core/lib/Drupal/Core/Test/PhpUnitTestRunner.php
index f238cf4d34560b73c888b91c9220d1c39de31877..e9103ceb9f47dc8eb4d7e8ac13a23d3222aa2289 100644
--- a/core/lib/Drupal/Core/Test/PhpUnitTestRunner.php
+++ b/core/lib/Drupal/Core/Test/PhpUnitTestRunner.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Database\Database;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\TestTools\Extension\DeprecationBridge\DeprecationHandler;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\Process\PhpExecutableFinder;
 use Symfony\Component\Process\Process;
@@ -18,7 +19,7 @@
  *
  * @code
  * $runner = PhpUnitTestRunner::create(\Drupal::getContainer());
- * $results = $runner->execute($test_run, $test_list['phpunit']);
+ * $results = $runner->execute($test_run, $test_class_name);
  * @endcode
  *
  * @internal
@@ -95,10 +96,9 @@ public function phpUnitCommand(): string {
   /**
    * Executes the PHPUnit command.
    *
-   * @param string[] $unescaped_test_classnames
-   *   An array of test class names, including full namespaces, to be passed as
-   *   a regular expression to PHPUnit's --filter option.
-   * @param string $phpunit_file
+   * @param string $test_class_name
+   *   A fully qualified test class name.
+   * @param string $log_junit_file_path
    *   A filepath to use for PHPUnit's --log-junit option.
    * @param int $status
    *   (optional) The exit status code of the PHPUnit process will be assigned
@@ -109,7 +109,7 @@ public function phpUnitCommand(): string {
    *
    * @internal
    */
-  public function runCommand(array $unescaped_test_classnames, string $phpunit_file, int &$status = NULL, array &$output = NULL): void {
+  protected function runCommand(string $test_class_name, string $log_junit_file_path, int &$status = NULL, array &$output = NULL): void {
     global $base_url;
     // Setup an environment variable containing the database connection so that
     // functional tests can connect to the database.
@@ -127,30 +127,24 @@ public function runCommand(array $unescaped_test_classnames, string $phpunit_fil
     }
     $phpunit_bin = $this->phpUnitCommand();
 
+    // Build the command line for the PHPUnit CLI invocation.
     $command = [
       $phpunit_bin,
       '--log-junit',
-      $phpunit_file,
+      $log_junit_file_path,
     ];
 
-    // Optimized for running a single test.
-    if (count($unescaped_test_classnames) == 1) {
-      $class = new \ReflectionClass($unescaped_test_classnames[0]);
-      $command[] = $class->getFileName();
+    // If the deprecation handler bridge is active, we need to fail when there
+    // are deprecations that get reported (i.e. not ignored or expected).
+    if (DeprecationHandler::getConfiguration() !== FALSE) {
+      $command[] = '--fail-on-deprecation';
     }
-    else {
-      // Double escape namespaces so they'll work in a regexp.
-      $escaped_test_classnames = array_map(function ($class) {
-        return addslashes($class);
-      }, $unescaped_test_classnames);
 
-      $filter_string = implode("|", $escaped_test_classnames);
-      $command = array_merge($command, [
-        '--filter',
-        $filter_string,
-      ]);
-    }
+    // Add to the command the file containing the test class to be run.
+    $reflectedClass = new \ReflectionClass($test_class_name);
+    $command[] = $reflectedClass->getFileName();
 
+    // Invoke PHPUnit CLI with the built command line.
     $process = new Process($command, \Drupal::root() . "/core", $process_environment_variables);
     $process->setTimeout(NULL);
     $process->run();
@@ -163,9 +157,8 @@ public function runCommand(array $unescaped_test_classnames, string $phpunit_fil
    *
    * @param \Drupal\Core\Test\TestRun $test_run
    *   The test run object.
-   * @param string[] $unescaped_test_classnames
-   *   An array of test class names, including full namespaces, to be passed as
-   *   a regular expression to PHPUnit's --filter option.
+   * @param string $test_class_name
+   *   A fully qualified test class name.
    * @param int $status
    *   (optional) The exit status code of the PHPUnit process will be assigned
    *   to this variable.
@@ -176,25 +169,25 @@ public function runCommand(array $unescaped_test_classnames, string $phpunit_fil
    *
    * @internal
    */
-  public function execute(TestRun $test_run, array $unescaped_test_classnames, int &$status = NULL): array {
-    $phpunit_file = $this->xmlLogFilePath($test_run->id());
+  public function execute(TestRun $test_run, string $test_class_name, int &$status = NULL): array {
+    $log_junit_file_path = $this->xmlLogFilePath($test_run->id());
     // Store output from our test run.
     $output = [];
-    $this->runCommand($unescaped_test_classnames, $phpunit_file, $status, $output);
+    $this->runCommand($test_class_name, $log_junit_file_path, $status, $output);
 
     if ($status == TestStatus::PASS) {
-      return JUnitConverter::xmlToRows($test_run->id(), $phpunit_file);
+      return JUnitConverter::xmlToRows($test_run->id(), $log_junit_file_path);
     }
     return [
       [
         'test_id' => $test_run->id(),
-        'test_class' => implode(",", $unescaped_test_classnames),
+        'test_class' => $test_class_name,
         'status' => TestStatus::label($status),
         'message' => 'PHPUnit Test failed to complete; Error: ' . implode("\n", $output),
         'message_group' => 'Other',
-        'function' => implode(",", $unescaped_test_classnames),
+        'function' => $test_class_name,
         'line' => '0',
-        'file' => $phpunit_file,
+        'file' => $log_junit_file_path,
       ],
     ];
   }
diff --git a/core/lib/Drupal/Core/Test/TestDiscovery.php b/core/lib/Drupal/Core/Test/TestDiscovery.php
index 9112d6e7abb165c4223cc7b7ecf7f4c962d42851..f63510a0d1a1013118f74281c4cc8d3efb32865c 100644
--- a/core/lib/Drupal/Core/Test/TestDiscovery.php
+++ b/core/lib/Drupal/Core/Test/TestDiscovery.php
@@ -7,7 +7,6 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Test\Exception\MissingGroupException;
-use Drupal\TestTools\PhpUnitCompatibility\ClassWriter;
 
 /**
  * Discovers available tests.
@@ -108,10 +107,6 @@ public function registerTestNamespaces() {
       $this->classLoader->addPsr4($prefix, $paths);
     }
 
-    $loader = require __DIR__ . '/../../../../../autoload.php';
-    // Ensure we have a valid TestCase class.
-    ClassWriter::mutateTestBase($loader);
-
     return $this->testNamespaces;
   }
 
diff --git a/core/lib/Drupal/Core/Test/TestRunnerKernel.php b/core/lib/Drupal/Core/Test/TestRunnerKernel.php
index e1729f8250100c7c0f14cde4d5244471d697a4e5..e5ece5c07a2b211cd42e2b95293ebf7eed4dcf53 100644
--- a/core/lib/Drupal/Core/Test/TestRunnerKernel.php
+++ b/core/lib/Drupal/Core/Test/TestRunnerKernel.php
@@ -5,6 +5,7 @@
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Extension\Extension;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\Utility\Error;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -60,7 +61,10 @@ public function boot() {
 
     // Remove Drupal's error/exception handlers; they are designed for HTML
     // and there is no storage nor a (watchdog) logger here.
-    restore_error_handler();
+    $currentErrorHandler = Error::currentErrorHandler();
+    if (is_string($currentErrorHandler) && $currentErrorHandler === '_drupal_error_handler') {
+      restore_error_handler();
+    }
     restore_exception_handler();
 
     // In addition, ensure that PHP errors are not hidden away in logs.
diff --git a/core/lib/Drupal/Core/Test/TestSetupTrait.php b/core/lib/Drupal/Core/Test/TestSetupTrait.php
index e1ff6eecd78327f3d51a54472d663721c9248653..e3bb02f10bcd5533679b3436cd9bebd1b93db7a2 100644
--- a/core/lib/Drupal/Core/Test/TestSetupTrait.php
+++ b/core/lib/Drupal/Core/Test/TestSetupTrait.php
@@ -170,6 +170,7 @@ protected function changeDatabasePrefix() {
         // prefixes of the test runner leak into the test.
         $connection_info[$target]['prefix'] = $value['prefix'] . $this->databasePrefix;
       }
+      Database::removeConnection('default');
       Database::addConnectionInfo('default', 'default', $connection_info['default']);
     }
   }
diff --git a/core/lib/Drupal/Core/Utility/Error.php b/core/lib/Drupal/Core/Utility/Error.php
index f8a54e20a2819f9703cd29208cf75008cc2a4592..459af44d8c517733e57c75b43b365f9534d09bb4 100644
--- a/core/lib/Drupal/Core/Utility/Error.php
+++ b/core/lib/Drupal/Core/Utility/Error.php
@@ -206,4 +206,16 @@ public static function formatBacktrace(array $backtrace) {
     return $return;
   }
 
+  /**
+   * Returns the current PHP error handler as a callable.
+   *
+   * @return callable|null
+   *   The current error handler as a callable, or NULL if none is set.
+   */
+  public static function currentErrorHandler(): ?callable {
+    $currentHandler = set_error_handler('var_dump');
+    restore_error_handler();
+    return $currentHandler;
+  }
+
 }
diff --git a/core/modules/language/tests/src/Unit/process/LanguageDomainsTest.php b/core/modules/language/tests/src/Unit/process/LanguageDomainsTest.php
index 8f6c3105ec59c849923881beedb2a9ae608a5efe..87f69db62352705ba720790501f5b941274321d7 100644
--- a/core/modules/language/tests/src/Unit/process/LanguageDomainsTest.php
+++ b/core/modules/language/tests/src/Unit/process/LanguageDomainsTest.php
@@ -13,11 +13,6 @@
  */
 class LanguageDomainsTest extends MigrateProcessTestCase {
 
-  /**
-   * {@inheritdoc}
-   */
-  protected $backupGlobalsBlacklist = ['base_url'];
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/tests/src/Functional/SecurityAdvisories/SecurityAdvisoryTest.php b/core/modules/system/tests/src/Functional/SecurityAdvisories/SecurityAdvisoryTest.php
index 1233fd2454260ed9a53721300575991689cf6666..248e57c74a305c819ddeaa87328222c0bb301591 100644
--- a/core/modules/system/tests/src/Functional/SecurityAdvisories/SecurityAdvisoryTest.php
+++ b/core/modules/system/tests/src/Functional/SecurityAdvisories/SecurityAdvisoryTest.php
@@ -118,7 +118,7 @@ protected function writeSettings(array $settings): void {
   public function testPsa(): void {
     $assert = $this->assertSession();
     // Setup test PSA endpoint.
-    AdvisoryTestClientMiddleware::setTestEndpoint($this->workingEndpointMixed);
+    AdvisoryTestClientMiddleware::setTestEndpoint($this->workingEndpointMixed, TRUE);
     $mixed_advisory_links = [
       'Critical Release - SA-2019-02-19',
       'Critical Release - PSA-Really Old',
diff --git a/core/phpunit.xml.dist b/core/phpunit.xml.dist
index c616c8c179f608d03bb9c546ddf8bf456595b3cf..4bfeb0086f62afd09fb4b3bd21fbb6ad3ec95bc6 100644
--- a/core/phpunit.xml.dist
+++ b/core/phpunit.xml.dist
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!-- For how to customize PHPUnit configuration, see core/tests/README.md. -->
 <!-- TODO set checkForUnintentionallyCoveredCode="true" once https://www.drupal.org/node/2626832 is resolved. -->
 <!-- PHPUnit expects functional tests to be run with either a privileged user
@@ -7,14 +6,18 @@
  https://www.drupal.org/node/2116263 for details.
 -->
 <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         bootstrap="tests/bootstrap.php" colors="true"
+         bootstrap="tests/bootstrap.php"
+         colors="true"
          beStrictAboutTestsThatDoNotTestAnything="true"
          beStrictAboutOutputDuringTests="true"
          beStrictAboutChangesToGlobalState="true"
          failOnWarning="true"
-         printerClass="\Drupal\Tests\Listeners\HtmlOutputPrinter"
+         displayDetailsOnTestsThatTriggerErrors="true"
+         displayDetailsOnTestsThatTriggerWarnings="true"
+         displayDetailsOnTestsThatTriggerDeprecations="true"
          cacheResult="false"
-         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
+         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
+         cacheDirectory=".phpunit.cache">
   <php>
     <!-- Set error reporting to E_ALL. -->
     <ini name="error_reporting" value="32767"/>
@@ -26,6 +29,13 @@
     <env name="SIMPLETEST_DB" value=""/>
     <!-- Example BROWSERTEST_OUTPUT_DIRECTORY value: /path/to/webroot/sites/simpletest/browser_output -->
     <env name="BROWSERTEST_OUTPUT_DIRECTORY" value=""/>
+    <!-- To avoid overcrowding the output in CI environments, browser tests
+     will not print the individual links in the test run report by default.
+     The output in Drupal testing environment is saved as an artifact that
+     can be browsed or downloaded from Gitlab. However, if you need to
+     print the individual links locally you can set the
+     BROWSERTEST_OUTPUT_VERBOSE environment variable to "true". -->
+    <!-- <env name="BROWSERTEST_OUTPUT_VERBOSE" value="true"/> -->
     <!-- By default, browser tests will output links that use the base URL set
      in SIMPLETEST_BASE_URL. However, if your SIMPLETEST_BASE_URL is an internal
      path (such as may be the case in a virtual or Docker-based environment),
@@ -33,11 +43,8 @@
      reachable from your host machine here. This will allow you to follow them
      directly and view the output. -->
     <env name="BROWSERTEST_OUTPUT_BASE_URL" value=""/>
-
-    <!-- Deprecation testing is managed through Symfony's PHPUnit Bridge.
-      The environment variable SYMFONY_DEPRECATIONS_HELPER is used to configure
+    <!-- The environment variable SYMFONY_DEPRECATIONS_HELPER is used to configure
       the behavior of the deprecation tests.
-      See https://symfony.com/doc/current/components/phpunit_bridge.html#configuration
       Drupal core's testing framework is setting this variable to its defaults.
       Projects with their own requirements need to manage this variable
       explicitly.
@@ -46,43 +53,61 @@
     <!-- <env name="SYMFONY_DEPRECATIONS_HELPER" value="disabled"/> -->
     <!-- Deprecation errors can be selectively ignored by specifying a file of
       regular expression patterns for exclusion.
-      See https://symfony.com/doc/current/components/phpunit_bridge.html#ignoring-deprecations
       Uncomment the line below to specify a custom deprecations ignore file.
       NOTE: it may be required to specify the full path to the file to run tests
       correctly.
     -->
     <!-- <env name="SYMFONY_DEPRECATIONS_HELPER" value="ignoreFile=.deprecation-ignore.txt"/> -->
-
     <!-- Example for changing the driver class for mink tests MINK_DRIVER_CLASS value: 'Drupal\FunctionalJavascriptTests\DrupalSelenium2Driver' -->
-    <env name="MINK_DRIVER_CLASS" value=''/>
+    <env name="MINK_DRIVER_CLASS" value=""/>
     <!-- Example for changing the driver args to mink tests MINK_DRIVER_ARGS value: '["http://127.0.0.1:8510"]' -->
-    <env name="MINK_DRIVER_ARGS" value=''/>
+    <env name="MINK_DRIVER_ARGS" value=""/>
     <!-- Example for changing the driver args to webdriver tests MINK_DRIVER_ARGS_WEBDRIVER value: '["chrome", { "goog:chromeOptions": { "w3c": false } }, "http://localhost:4444/wd/hub"]' For using the Firefox browser, replace "chrome" with "firefox" -->
-    <env name="MINK_DRIVER_ARGS_WEBDRIVER" value=''/>
+    <env name="MINK_DRIVER_ARGS_WEBDRIVER" value=""/>
   </php>
   <testsuites>
     <testsuite name="unit">
-      <file>./tests/TestSuites/UnitTestSuite.php</file>
+      <directory>tests/Drupal/Tests</directory>
+      <directory>modules/**/tests/src/Unit</directory>
+      <directory>profiles/**/tests/src/Unit</directory>
+      <directory>themes/**/tests/src/Unit</directory>
+      <directory>../modules/**/tests/src/Unit</directory>
+      <directory>../profiles/**/tests/src/Unit</directory>
+      <directory>../themes/**/tests/src/Unit</directory>
     </testsuite>
     <testsuite name="kernel">
-      <file>./tests/TestSuites/KernelTestSuite.php</file>
+      <directory>tests/Drupal/KernelTests</directory>
+      <directory>modules/**/tests/src/Kernel</directory>
+      <directory>profiles/**/tests/src/Kernel</directory>
+      <directory>themes/**/tests/src/Kernel</directory>
+      <directory>../modules/**/tests/src/Kernel</directory>
+      <directory>../profiles/**/tests/src/Kernel</directory>
+      <directory>../themes/**/tests/src/Kernel</directory>
     </testsuite>
     <testsuite name="functional">
-      <file>./tests/TestSuites/FunctionalTestSuite.php</file>
+      <directory>tests/Drupal/FunctionalTests</directory>
+      <directory>modules/**/tests/src/Functional</directory>
+      <directory>profiles/**/tests/src/Functional</directory>
+      <directory>themes/**/tests/src/Functional</directory>
+      <directory>../modules/**/tests/src/Functional</directory>
+      <directory>../profiles/**/tests/src/Functional</directory>
+      <directory>../themes/**/tests/src/Functional</directory>
     </testsuite>
     <testsuite name="functional-javascript">
-      <file>./tests/TestSuites/FunctionalJavascriptTestSuite.php</file>
+      <directory>tests/Drupal/FunctionalJavascriptTests</directory>
+      <directory>modules/**/tests/src/FunctionalJavascript</directory>
+      <directory>profiles/**/tests/src/FunctionalJavascript</directory>
+      <directory>themes/**/tests/src/FunctionalJavascript</directory>
+      <directory>../modules/**/tests/src/FunctionalJavascript</directory>
+      <directory>../profiles/**/tests/src/FunctionalJavascript</directory>
+      <directory>../themes/**/tests/src/FunctionalJavascript</directory>
     </testsuite>
     <testsuite name="build">
-      <file>./tests/TestSuites/BuildTestSuite.php</file>
+      <directory>tests/Drupal/BuildTests</directory>
     </testsuite>
   </testsuites>
-  <listeners>
-    <listener class="\Drupal\Tests\Listeners\DrupalListener">
-    </listener>
-  </listeners>
   <!-- Settings for coverage reports. -->
-  <coverage>
+  <source ignoreSuppressionOfDeprecations="true">
     <include>
       <directory>./includes</directory>
       <directory>./lib</directory>
@@ -101,5 +126,5 @@
       <directory suffix=".api.php">./modules/**</directory>
       <directory suffix=".api.php">../modules/**</directory>
     </exclude>
-  </coverage>
+  </source>
 </phpunit>
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 56ad3e553f4db6cfd51ee519084a162c7245646b..0672c44d85f7817f25e8ec2f65b30ce6c3ce5f71 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -25,7 +25,6 @@
 use Drupal\Core\Test\TestRunnerKernel;
 use Drupal\Core\Test\TestRunResultsStorageInterface;
 use Drupal\Core\Test\TestDiscovery;
-use Drupal\TestTools\PhpUnitCompatibility\ClassWriter;
 use PHPUnit\Framework\TestCase;
 use PHPUnit\Runner\Version;
 use Symfony\Component\Console\Output\ConsoleOutput;
@@ -511,7 +510,6 @@ function simpletest_script_init() {
   $autoloader = require_once __DIR__ . '/../../autoload.php';
   // The PHPUnit compatibility layer needs to be available to autoload tests.
   $autoloader->add('Drupal\\TestTools', __DIR__ . '/../tests');
-  ClassWriter::mutateTestBase($autoloader);
 
   // Get URL from arguments.
   if (!empty($args['url'])) {
@@ -817,13 +815,8 @@ function simpletest_script_execute_batch(TestRunResultsStorageInterface $test_ru
  * Run a PHPUnit-based test.
  */
 function simpletest_script_run_phpunit(TestRun $test_run, $class) {
-  $reflection = new \ReflectionClass($class);
-  if ($reflection->hasProperty('runLimit')) {
-    set_time_limit($reflection->getStaticPropertyValue('runLimit'));
-  }
-
   $runner = PhpUnitTestRunner::create(\Drupal::getContainer());
-  $results = $runner->execute($test_run, [$class], $status);
+  $results = $runner->execute($test_run, $class, $status);
   $runner->processPhpUnitResults($test_run, $results);
 
   $summaries = $runner->summarizeResults($results);
diff --git a/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php b/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php
index f0cb552acf3629dfa10504e58835f5ba9d793e31..afdd7fcbcb552112e74cadb73723875c49c3787e 100644
--- a/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php
+++ b/core/tests/Drupal/BuildTests/Framework/BuildTestBase.php
@@ -11,7 +11,6 @@
 use Drupal\Component\FileSystem\FileSystem as DrupalFilesystem;
 use Drupal\Tests\DrupalTestBrowser;
 use Drupal\Tests\PhpUnitCompatibilityTrait;
-use Drupal\Tests\Traits\PhpUnitWarnings;
 use Drupal\TestTools\Extension\RequiresComposerTrait;
 use PHPUnit\Framework\TestCase;
 use Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem;
@@ -55,7 +54,6 @@
 abstract class BuildTestBase extends TestCase {
 
   use RequiresComposerTrait;
-  use PhpUnitWarnings;
   use PhpUnitCompatibilityTrait;
 
   /**
diff --git a/core/tests/Drupal/BuildTests/Framework/Tests/BuildTestTest.php b/core/tests/Drupal/BuildTests/Framework/Tests/BuildTestTest.php
index c55ae1580ebd0d4ded90cc48e31c4f03eaedc4ea..4803397db446fb3009b80378bcb52eb7e5a219b7 100644
--- a/core/tests/Drupal/BuildTests/Framework/Tests/BuildTestTest.php
+++ b/core/tests/Drupal/BuildTests/Framework/Tests/BuildTestTest.php
@@ -92,6 +92,7 @@ public function testCopyCodebaseExclude() {
     /** @var \PHPUnit\Framework\MockObject\MockBuilder|\Drupal\BuildTests\Framework\BuildTestBase $base */
     $base = $this->getMockBuilder(BuildTestBase::class)
       ->onlyMethods(['getDrupalRoot', 'getComposerRoot'])
+      ->setConstructorArgs(['test'])
       ->getMockForAbstractClass();
     $base->expects($this->exactly(1))
       ->method('getDrupalRoot')
@@ -170,6 +171,7 @@ public function testCopyCodebaseDocRoot() {
     /** @var \PHPUnit\Framework\MockObject\MockBuilder|\Drupal\BuildTests\Framework\BuildTestBase $base */
     $base = $this->getMockBuilder(BuildTestBase::class)
       ->onlyMethods(['getDrupalRoot', 'getComposerRoot'])
+      ->setConstructorArgs(['test'])
       ->getMockForAbstractClass();
     $base->expects($this->exactly(3))
       ->method('getDrupalRoot')
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/WebDriverTestBase.php b/core/tests/Drupal/FunctionalJavascriptTests/WebDriverTestBase.php
index 9ec27626137cb0446ef0747389102652c75b01a8..d8f0b3d2de65f2cb887a247b8d5ffb26700a24d7 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/WebDriverTestBase.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/WebDriverTestBase.php
@@ -7,7 +7,6 @@
 use Behat\Mink\Exception\DriverException;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Tests\BrowserTestBase;
-use PHPUnit\Runner\BaseTestRunner;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -96,11 +95,6 @@ protected function initFrontPage() {
    */
   protected function tearDown(): void {
     if ($this->mink) {
-      $status = $this->getStatus();
-      if ($status === BaseTestRunner::STATUS_ERROR || $status === BaseTestRunner::STATUS_WARNING || $status === BaseTestRunner::STATUS_FAILURE) {
-        // Ensure we capture the output at point of failure.
-        @$this->htmlOutput();
-      }
       // Wait for all requests to finish. It is possible that an AJAX request is
       // still on-going.
       $result = $this->getSession()->wait(5000, 'window.drupalActiveXhrCount === 0 || typeof window.drupalActiveXhrCount === "undefined"');
diff --git a/core/tests/Drupal/FunctionalTests/Core/Test/PhpUnitBridgeTest.php b/core/tests/Drupal/FunctionalTests/Core/Test/PhpUnitBridgeTest.php
index f978361cf4c268869e4c6bb3a7e7953bb4d9e14d..a674fa7a8a5f911aa613285c98959c9c90b4336e 100644
--- a/core/tests/Drupal/FunctionalTests/Core/Test/PhpUnitBridgeTest.php
+++ b/core/tests/Drupal/FunctionalTests/Core/Test/PhpUnitBridgeTest.php
@@ -8,7 +8,7 @@
 use Drupal\Tests\BrowserTestBase;
 
 /**
- * Tests Drupal's integration with Symfony PHPUnit Bridge.
+ * Tests Drupal's extension to manage code deprecation.
  *
  * @group Test
  * @group legacy
diff --git a/core/tests/Drupal/FunctionalTests/Installer/SuperUserAccessInstallTest.php b/core/tests/Drupal/FunctionalTests/Installer/SuperUserAccessInstallTest.php
index a327866f16a641f7c6c5754599d6a31e60e3cb97..dd99caf01fd8ba45394ada723215744acb5bffa7 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/SuperUserAccessInstallTest.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/SuperUserAccessInstallTest.php
@@ -46,10 +46,10 @@ protected function prepareEnvironment() {
     mkdir($path, 0777, TRUE);
     file_put_contents("$path/superuser.info.yml", Yaml::encode($info));
 
-    file_put_contents("$path/superuser.install", $this->getProvidedData()['install_code']);
+    file_put_contents("$path/superuser.install", $this->providedData()['install_code']);
 
     $services = Yaml::decode(file_get_contents(DRUPAL_ROOT . '/sites/default/default.services.yml'));
-    $services['parameters']['security.enable_super_user'] = $this->getProvidedData()['super_user_policy'];
+    $services['parameters']['security.enable_super_user'] = $this->providedData()['super_user_policy'];
     file_put_contents(DRUPAL_ROOT . '/' . $this->siteDirectory . '/services.yml', Yaml::encode($services));
   }
 
@@ -57,7 +57,7 @@ protected function prepareEnvironment() {
    * {@inheritdoc}
    */
   protected function setUpSite() {
-    if ($this->getProvidedData()['super_user_policy'] === FALSE && empty($this->getProvidedData()['expected_roles'])) {
+    if ($this->providedData()['super_user_policy'] === FALSE && empty($this->providedData()['expected_roles'])) {
       $this->assertSession()->pageTextContains('Site account');
       $this->assertSession()->pageTextNotContains('Site maintenance account');
     }
diff --git a/core/tests/Drupal/FunctionalTests/Test/FunctionalTestDebugHtmlOutputTest.php b/core/tests/Drupal/FunctionalTests/Test/FunctionalTestDebugHtmlOutputTest.php
index ae88182aa68f5733f0932aad37c94e80d4e5f888..53c3d130b64ba653ec5e4fc666e1f6764198d972 100644
--- a/core/tests/Drupal/FunctionalTests/Test/FunctionalTestDebugHtmlOutputTest.php
+++ b/core/tests/Drupal/FunctionalTests/Test/FunctionalTestDebugHtmlOutputTest.php
@@ -26,8 +26,15 @@ class FunctionalTestDebugHtmlOutputTest extends BrowserTestBase {
    * running a functional test are met.
    */
   public function testFunctionalTestDebugHtmlOutput(): void {
-    // Test with the specified output directory.
-    $process = Process::fromShellCommandline('vendor/bin/phpunit --configuration core --verbose core/tests/Drupal/FunctionalTests/Test/FunctionalTestDebugHtmlOutputHelperTest.php');
+    $command = [
+      'vendor/bin/phpunit',
+      '--configuration',
+      'core',
+      'core/tests/Drupal/FunctionalTests/Test/FunctionalTestDebugHtmlOutputHelperTest.php',
+    ];
+
+    // Test with the default output directory, specified by BROWSERTEST_OUTPUT_DIRECTORY.
+    $process = new Process($command);
     $process->setWorkingDirectory($this->root)
       ->setTimeout(300)
       ->setIdleTimeout(300);
@@ -36,15 +43,31 @@ public function testFunctionalTestDebugHtmlOutput(): void {
       'COMMAND: ' . $process->getCommandLine() . "\n" .
       'OUTPUT: ' . $process->getOutput() . "\n" .
       'ERROR: ' . $process->getErrorOutput() . "\n");
-    $this->assertStringContainsString('HTML output was generated', $process->getOutput());
+    $this->assertMatchesRegularExpression('/HTML output was generated, \d+ page\(s\)\./m', $process->getOutput());
+
+    // Test with verbose output.
+    $process = new Process($command);
+    $process->setWorkingDirectory($this->root)
+      ->setTimeout(300)
+      ->setIdleTimeout(300);
+    $process->run(NULL, [
+      'BROWSERTEST_OUTPUT_VERBOSE' => '1',
+    ]);
+    $this->assertEquals(0, $process->getExitCode(),
+      'COMMAND: ' . $process->getCommandLine() . "\n" .
+      'OUTPUT: ' . $process->getOutput() . "\n" .
+      'ERROR: ' . $process->getErrorOutput() . "\n");
+    $this->assertStringContainsString('HTML output was generated.', $process->getOutput());
     $this->assertStringContainsString('Drupal_FunctionalTests_Test_FunctionalTestDebugHtmlOutputHelperTest', $process->getOutput());
 
     // Test with a wrong output directory.
-    $process = Process::fromShellCommandline('vendor/bin/phpunit --configuration core --verbose core/tests/Drupal/FunctionalTests/Test/FunctionalTestDebugHtmlOutputHelperTest.php');
+    $process = new Process($command);
     $process->setWorkingDirectory($this->root)
       ->setTimeout(300)
       ->setIdleTimeout(300);
-    $process->run(NULL, ['BROWSERTEST_OUTPUT_DIRECTORY' => 'can_we_assume_that_a_subdirectory_with_this_name_does_not_exist']);
+    $process->run(NULL, [
+      'BROWSERTEST_OUTPUT_DIRECTORY' => 'can_we_assume_that_a_subdirectory_with_this_name_does_not_exist',
+    ]);
     $this->assertEquals(0, $process->getExitCode(),
       'COMMAND: ' . $process->getCommandLine() . "\n" .
       'OUTPUT: ' . $process->getOutput() . "\n" .
diff --git a/core/tests/Drupal/KernelTests/Core/DrupalKernel/DrupalKernelSiteTest.php b/core/tests/Drupal/KernelTests/Core/DrupalKernel/DrupalKernelSiteTest.php
index be7bf3c28fe93d73002af8078d7286edd755338a..c58461ea29eecacc9ca1efbc206d14fc09c7451b 100644
--- a/core/tests/Drupal/KernelTests/Core/DrupalKernel/DrupalKernelSiteTest.php
+++ b/core/tests/Drupal/KernelTests/Core/DrupalKernel/DrupalKernelSiteTest.php
@@ -38,6 +38,7 @@ class: Drupal\Component\Datetime\Time
   # Add a new service.
   site.service.yml:
     class: $class
+    arguments: ['test']
   # Swap out a core service.
   cache.backend.database:
     class: Drupal\Core\Cache\MemoryBackendFactory
diff --git a/core/tests/Drupal/KernelTests/Core/DrupalKernel/DrupalKernelTest.php b/core/tests/Drupal/KernelTests/Core/DrupalKernel/DrupalKernelTest.php
index ec94d2fc52ef3ffe8ffa52623f5b49bc2cd4d8ef..e3d3b2f5d2eed0226325a092a19d6730895ad673 100644
--- a/core/tests/Drupal/KernelTests/Core/DrupalKernel/DrupalKernelTest.php
+++ b/core/tests/Drupal/KernelTests/Core/DrupalKernel/DrupalKernelTest.php
@@ -7,6 +7,7 @@
 use Composer\Autoload\ClassLoader;
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\DrupalKernelInterface;
+use Drupal\Core\Utility\Error;
 use Drupal\KernelTests\KernelTestBase;
 use org\bovigo\vfs\vfsStream;
 use Prophecy\Argument;
@@ -22,6 +23,17 @@
  */
 class DrupalKernelTest extends KernelTestBase {
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown(): void {
+    $currentErrorHandler = Error::currentErrorHandler();
+    if (is_string($currentErrorHandler) && $currentErrorHandler === '_drupal_error_handler') {
+      restore_error_handler();
+    }
+    parent::tearDown();
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/tests/Drupal/KernelTests/KernelTestBase.php b/core/tests/Drupal/KernelTests/KernelTestBase.php
index 5f24dc24e5759c3ddf5842070e09c4a76803eb75..0ccee09bbe52126d3ed64a4d219f66177dfe7996 100644
--- a/core/tests/Drupal/KernelTests/KernelTestBase.php
+++ b/core/tests/Drupal/KernelTests/KernelTestBase.php
@@ -23,8 +23,8 @@
 use Drupal\Tests\RandomGeneratorTrait;
 use Drupal\Tests\PhpUnitCompatibilityTrait;
 use Drupal\Tests\TestRequirementsTrait;
-use Drupal\Tests\Traits\PhpUnitWarnings;
 use Drupal\TestTools\Comparator\MarkupInterfaceComparator;
+use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
 use Drupal\TestTools\Extension\SchemaInspector;
 use Drupal\TestTools\TestVarDumper;
 use PHPUnit\Framework\Exception;
@@ -38,7 +38,6 @@
 use Drupal\Core\Routing\RouteObjectInterface;
 use Symfony\Component\Routing\Route;
 use Symfony\Component\VarDumper\VarDumper;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
 
 /**
  * Base class for functional integration tests.
@@ -91,7 +90,6 @@ abstract class KernelTestBase extends TestCase implements ServiceProviderInterfa
   use ConfigTestTrait;
   use ExtensionListTestTrait;
   use TestRequirementsTrait;
-  use PhpUnitWarnings;
   use PhpUnitCompatibilityTrait;
   use ProphecyTrait;
   use ExpectDeprecationTrait;
@@ -99,30 +97,19 @@ abstract class KernelTestBase extends TestCase implements ServiceProviderInterfa
   /**
    * {@inheritdoc}
    *
-   * Back up and restore any global variables that may be changed by tests.
+   * Back up and restore static class properties that may be changed by tests.
    *
    * @see self::runTestInSeparateProcess
    */
-  protected $backupGlobals = TRUE;
-
-  /**
-   * {@inheritdoc}
-   *
-   * Kernel tests are run in separate processes because they allow autoloading
-   * of code from extensions. Running the test in a separate process isolates
-   * this behavior from other tests. Subclasses should not override this
-   * property.
-   */
-  protected $runTestInSeparateProcess = TRUE;
+  protected $backupStaticAttributes = TRUE;
 
   /**
    * {@inheritdoc}
-   *
-   * Back up and restore static class properties that may be changed by tests.
-   *
-   * @see self::runTestInSeparateProcess
    */
-  protected $backupStaticAttributes = TRUE;
+  public function __construct(string $name) {
+    parent::__construct($name);
+    $this->setRunTestInSeparateProcess(TRUE);
+  }
 
   /**
    * {@inheritdoc}
@@ -141,16 +128,6 @@ abstract class KernelTestBase extends TestCase implements ServiceProviderInterfa
     'Drupal\Core\Site\Settings' => ['instance'],
   ];
 
-  /**
-   * {@inheritdoc}
-   *
-   * Do not forward any global state from the parent process to the processes
-   * that run the actual tests.
-   *
-   * @see self::runTestInSeparateProcess
-   */
-  protected $preserveGlobalState = FALSE;
-
   /**
    * @var \Composer\Autoload\Classloader
    */
diff --git a/core/tests/Drupal/KernelTests/KernelTestBaseTest.php b/core/tests/Drupal/KernelTests/KernelTestBaseTest.php
index fe71a5b2d1d5b300c06c43d42ea749e9c674c095..55c27fa4c0cac8c3a1b21427b3d5aa0ce964126c 100644
--- a/core/tests/Drupal/KernelTests/KernelTestBaseTest.php
+++ b/core/tests/Drupal/KernelTests/KernelTestBaseTest.php
@@ -75,9 +75,6 @@ public function testSetUp() {
 
     $this->assertEquals($this, $GLOBALS['conf']['container_service_providers']['test']);
 
-    $GLOBALS['destroy-me'] = TRUE;
-    $this->assertArrayHasKey('destroy-me', $GLOBALS);
-
     $database = $this->container->get('database');
     $database->schema()->createTable('foo', [
       'fields' => [
@@ -98,8 +95,6 @@ public function testSetUp() {
    * @depends testSetUp
    */
   public function testSetUpDoesNotLeak() {
-    $this->assertArrayNotHasKey('destroy-me', $GLOBALS);
-
     // Ensure that we have a different database prefix.
     $schema = $this->container->get('database')->schema();
     $this->assertFalse($schema->tableExists('foo'));
diff --git a/core/tests/Drupal/TestTools/Comparator/MarkupInterfaceComparator.php b/core/tests/Drupal/TestTools/Comparator/MarkupInterfaceComparator.php
index 174f2447ad5a002834ecc7aff490caa6acf59984..50e60f5dca9835e2aff242c89d1b93dfc1a212a6 100644
--- a/core/tests/Drupal/TestTools/Comparator/MarkupInterfaceComparator.php
+++ b/core/tests/Drupal/TestTools/Comparator/MarkupInterfaceComparator.php
@@ -42,7 +42,7 @@ public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = F
         throw new \RuntimeException("Cannot compare markup between MarkupInterface objects and plain strings");
       }
     }
-    $comparator = $this->factory->getComparatorFor($expected_safe_stripped, $actual_safe_stripped);
+    $comparator = $this->factory()->getComparatorFor($expected_safe_stripped, $actual_safe_stripped);
     $comparator->assertEquals($expected_safe_stripped, $actual_safe_stripped, $delta, $canonicalize, $ignoreCase);
   }
 
diff --git a/core/tests/Drupal/TestTools/ErrorHandler/BootstrapErrorHandler.php b/core/tests/Drupal/TestTools/ErrorHandler/BootstrapErrorHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..ab3d0c8a1c3c08bd77669babdf023e4d37965ef1
--- /dev/null
+++ b/core/tests/Drupal/TestTools/ErrorHandler/BootstrapErrorHandler.php
@@ -0,0 +1,84 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\TestTools\ErrorHandler;
+
+use Drupal\TestTools\Extension\DeprecationBridge\DeprecationHandler;
+use PHPUnit\Event\Code\NoTestCaseObjectOnCallStackException;
+use PHPUnit\Runner\ErrorHandler as PhpUnitErrorHandler;
+
+/**
+ * Drupal's PHPUnit base error handler.
+ *
+ * This code works in coordination with DeprecationHandler.
+ *
+ * This error handler is registered during PHPUnit's runner bootstrap, and is
+ * essentially used to capture deprecations occurring before tests are run (for
+ * example, deprecations triggered by the DebugClassloader). When test runs
+ * are prepared, a test specific TestErrorHandler is activated instead.
+ *
+ * @see \Drupal\TestTools\Extension\DeprecationBridge\DeprecationHandler
+ *
+ * @internal
+ */
+final class BootstrapErrorHandler {
+
+  /**
+   * @param \PHPUnit\Runner\ErrorHandler $phpUnitErrorHandler
+   *   An instance of PHPUnit's runner own error handler. Any error not
+   *   managed here will fall back to it.
+   */
+  public function __construct(
+    private readonly PhpUnitErrorHandler $phpUnitErrorHandler,
+  ) {
+  }
+
+  /**
+   * Executes when the object is called as a function.
+   *
+   * @param int $errorNumber
+   *   The level of the error raised.
+   * @param string $errorString
+   *   The error message.
+   * @param string $errorFile
+   *   The filename that the error was raised in.
+   * @param int $errorLine
+   *   The line number the error was raised at.
+   *
+   * @return bool
+   *   TRUE to stop error handling, FALSE to let the normal error handler
+   *   continue.
+   */
+  public function __invoke(int $errorNumber, string $errorString, string $errorFile, int $errorLine): bool {
+    if (!DeprecationHandler::isEnabled()) {
+      throw new \RuntimeException(__METHOD__ . '() must not be called if the deprecation handler is not enabled.');
+    }
+
+    // We collect a deprecation no matter what.
+    if (E_USER_DEPRECATED === $errorNumber || E_DEPRECATED === $errorNumber) {
+      $prefix = (error_reporting() & $errorNumber) ? 'Unsilenced deprecation: ' : '';
+      DeprecationHandler::collectActualDeprecation($prefix . $errorString);
+    }
+
+    // If the deprecation handled is one of those in the ignore list, we keep
+    // running.
+    if ((E_USER_DEPRECATED === $errorNumber || E_DEPRECATED === $errorNumber) && DeprecationHandler::isIgnoredDeprecation($errorString)) {
+      return TRUE;
+    }
+
+    // In all other cases (errors, warnings, deprecations to be reported), we
+    // fall back to PHPUnit's error handler, an instance of which was created
+    // when this error handler was created.
+    try {
+      call_user_func($this->phpUnitErrorHandler, $errorNumber, $errorString, $errorFile, $errorLine);
+    }
+    catch (NoTestCaseObjectOnCallStackException $e) {
+      // If we end up here, it's likely because a test's processing has
+      // finished already and we are processing an error that occurred while
+      // dealing with STDOUT rewinding or truncating. Do nothing.
+    }
+    return TRUE;
+  }
+
+}
diff --git a/core/tests/Drupal/TestTools/ErrorHandler/TestErrorHandler.php b/core/tests/Drupal/TestTools/ErrorHandler/TestErrorHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..8ad1de3f634eefc5ba577b6b256c2ebc6a05dd9f
--- /dev/null
+++ b/core/tests/Drupal/TestTools/ErrorHandler/TestErrorHandler.php
@@ -0,0 +1,75 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\TestTools\ErrorHandler;
+
+use Drupal\TestTools\Extension\DeprecationBridge\DeprecationHandler;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Drupal's PHPUnit test level error handler.
+ *
+ * This code works in coordination with DeprecationHandler.
+ *
+ * This error handler is registered during the preparation of a PHPUnit's test,
+ * and is essentially used to capture deprecations occurring during test
+ * executions. When test runs are torn down, the more generic
+ * BootstrapErrorHandler is restored.
+ *
+ * @see \Drupal\TestTools\Extension\DeprecationBridge\DeprecationHandler
+ *
+ * @internal
+ */
+final class TestErrorHandler {
+
+  /**
+   * @param \Drupal\TestTools\ErrorHandler\BootstrapErrorHandler $parentHandler
+   *   The parent error handler.
+   * @param \PHPUnit\Framework\TestCase $testCase
+   *   The test case being executed.
+   */
+  public function __construct(
+    private readonly BootstrapErrorHandler $parentHandler,
+    private readonly TestCase $testCase,
+  ) {
+  }
+
+  /**
+   * Executes when the object is called as a function.
+   *
+   * @param int $errorNumber
+   *   The level of the error raised.
+   * @param string $errorString
+   *   The error message.
+   * @param string $errorFile
+   *   The filename that the error was raised in.
+   * @param int $errorLine
+   *   The line number the error was raised at.
+   *
+   * @return bool
+   *   TRUE to stop error handling, FALSE to let the normal error handler
+   *   continue.
+   */
+  public function __invoke(int $errorNumber, string $errorString, string $errorFile, int $errorLine): bool {
+    if (!DeprecationHandler::isEnabled()) {
+      throw new \RuntimeException(__METHOD__ . '() must not be called if the deprecation handler is not enabled.');
+    }
+
+    // We are within a test execution. If we have a deprecation and the test is
+    // a deprecation test, than we just collect the deprecation and return to
+    // execution, since deprecations are expected.
+    if ((E_USER_DEPRECATED === $errorNumber || E_DEPRECATED === $errorNumber) && DeprecationHandler::isDeprecationTest($this->testCase)) {
+      $prefix = (error_reporting() & $errorNumber) ? 'Unsilenced deprecation: ' : '';
+      DeprecationHandler::collectActualDeprecation($prefix . $errorString);
+      return TRUE;
+    }
+
+    // In all other cases (errors, warnings, deprecations in normal tests), we
+    // fall back to the parent error handler, which is the one that was
+    // registered in the test runner bootstrap (BootstrapErrorHandler).
+    call_user_func($this->parentHandler, $errorNumber, $errorString, $errorFile, $errorLine);
+    return TRUE;
+  }
+
+}
diff --git a/core/tests/Drupal/TestTools/Extension/DeprecationBridge/DeprecationHandler.php b/core/tests/Drupal/TestTools/Extension/DeprecationBridge/DeprecationHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..c176980bae27936318e83bd9b72540700a6952a7
--- /dev/null
+++ b/core/tests/Drupal/TestTools/Extension/DeprecationBridge/DeprecationHandler.php
@@ -0,0 +1,249 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\TestTools\Extension\DeprecationBridge;
+
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Drupal's PHPUnit extension to manage code deprecation.
+ *
+ * This class is a replacement for symfony/phpunit-bridge that does not
+ * support PHPUnit 10. In the future this extension might be dropped if
+ * PHPUnit adds support for all deprecation management needs.
+ *
+ * @internal
+ */
+final class DeprecationHandler {
+
+  /**
+   * Indicates if the extension is enabled.
+   */
+  private static bool $enabled = FALSE;
+
+  /**
+   * A list of deprecation messages that should be ignored if detected.
+   *
+   * @var list<string>
+   */
+  private static array $deprecationIgnorePatterns = [];
+
+  /**
+   * A list of expected deprecation messages.
+   *
+   * @var list<string>
+   */
+  private static array $expectedDeprecations = [];
+
+  /**
+   * A list of deprecation messages collected during test run.
+   *
+   * @var list<string>
+   */
+  private static array $collectedDeprecations = [];
+
+  /**
+   * This class should not be instantiated.
+   */
+  private function __construct() {
+    throw new \LogicException(__CLASS__ . ' should not be instantiated');
+  }
+
+  /**
+   * Returns the extension configuration.
+   *
+   * For historical reasons, the configuration is stored in the
+   * SYMFONY_DEPRECATIONS_HELPER environment variable.
+   *
+   * @return array|false
+   *   An array of configuration variables, of FALSE if the extension is
+   *   disabled.
+   */
+  public static function getConfiguration(): array|FALSE {
+    $environmentVariable = getenv('SYMFONY_DEPRECATIONS_HELPER');
+    if ($environmentVariable === 'disabled') {
+      return FALSE;
+    }
+    if ($environmentVariable === FALSE) {
+      // Ensure ignored deprecation patterns listed in .deprecation-ignore.txt
+      // are considered in testing.
+      $relativeFilePath = __DIR__ . "/../../../../../.deprecation-ignore.txt";
+      $deprecationIgnoreFilename = realpath($relativeFilePath);
+      if (empty($deprecationIgnoreFilename)) {
+        throw new \InvalidArgumentException(sprintf('The ignoreFile "%s" does not exist.', $relativeFilePath));
+      }
+      $environmentVariable = "ignoreFile=$deprecationIgnoreFilename";
+    }
+    parse_str($environmentVariable, $configuration);
+    return $configuration;
+  }
+
+  /**
+   * Determines if the extension is enabled.
+   *
+   * @return bool
+   *   TRUE if enabled, FALSE if disabled.
+   */
+  public static function isEnabled(): bool {
+    return self::$enabled;
+  }
+
+  /**
+   * Initializes the extension.
+   *
+   * @param string|null $ignoreFile
+   *   The path to a file containing ignore patterns for deprecations.
+   */
+  public static function init(?string $ignoreFile = NULL): void {
+    if (self::isEnabled()) {
+      throw new \LogicException(__CLASS__ . ' is already initialized');
+    }
+
+    // Load the deprecation ignore patterns from the specified file.
+    if ($ignoreFile && !self::$deprecationIgnorePatterns) {
+      if (!is_file($ignoreFile)) {
+        throw new \InvalidArgumentException(sprintf('The ignoreFile "%s" does not exist.', $ignoreFile));
+      }
+      set_error_handler(static function ($t, $m) use ($ignoreFile, &$line) {
+        throw new \RuntimeException(sprintf('Invalid pattern found in "%s" on line "%d"', $ignoreFile, 1 + $line) . substr($m, 12));
+      });
+      try {
+        foreach (file($ignoreFile) as $line => $pattern) {
+          if ((trim($pattern)[0] ?? '#') !== '#') {
+            preg_match($pattern, '');
+            self::$deprecationIgnorePatterns[] = $pattern;
+          }
+        }
+      }
+      finally {
+        restore_error_handler();
+      }
+    }
+
+    // Mark the extension as enabled.
+    self::$enabled = TRUE;
+  }
+
+  /**
+   * Resets the extension.
+   *
+   * The extension should be reset at the beginning of each test run to ensure
+   * matching of expected and actual deprecations.
+   */
+  public static function reset(): void {
+    if (!self::isEnabled()) {
+      return;
+    }
+    self::$expectedDeprecations = [];
+    self::$collectedDeprecations = [];
+  }
+
+  /**
+   * Adds an expected deprecation.
+   *
+   * Tests will expect deprecations during the test execution; at the end of
+   * each test run, collected deprecations are checked against the expected
+   * ones.
+   *
+   * @param string $message
+   *   The expected deprecation message.
+   */
+  public static function expectDeprecation(string $message): void {
+    if (!self::isEnabled()) {
+      return;
+    }
+    self::$expectedDeprecations[] = $message;
+  }
+
+  /**
+   * Returns all expected deprecations.
+   *
+   * @return list<string>
+   *   The expected deprecation messages.
+   */
+  public static function getExpectedDeprecations(): array {
+    if (!self::isEnabled()) {
+      throw new \LogicException(__CLASS__ . ' is not initialized');
+    }
+    return self::$expectedDeprecations;
+  }
+
+  /**
+   * Collects an actual deprecation.
+   *
+   * Tests will expect deprecations during the test execution; at the end of
+   * each test run, collected deprecations are checked against the expected
+   * ones.
+   *
+   * @param string $message
+   *   The actual deprecation message triggered via trigger_error().
+   */
+  public static function collectActualDeprecation(string $message): void {
+    if (!self::isEnabled()) {
+      return;
+    }
+    self::$collectedDeprecations[] = $message;
+  }
+
+  /**
+   * Returns all collected deprecations.
+   *
+   * @return list<string>
+   *   The collected deprecation messages.
+   */
+  public static function getCollectedDeprecations(): array {
+    if (!self::isEnabled()) {
+      throw new \LogicException(__CLASS__ . ' is not initialized');
+    }
+    return self::$collectedDeprecations;
+  }
+
+  /**
+   * Determines if an actual deprecation should be ignored.
+   *
+   * Deprecations that match the patterns included in the ignore file should
+   * be ignored.
+   *
+   * @param string $deprecationMessage
+   *   The actual deprecation message triggered via trigger_error().
+   */
+  public static function isIgnoredDeprecation(string $deprecationMessage): bool {
+    if (!self::$deprecationIgnorePatterns) {
+      return FALSE;
+    }
+    $result = @preg_filter(self::$deprecationIgnorePatterns, '$0', $deprecationMessage);
+    if (preg_last_error() !== \PREG_NO_ERROR) {
+      throw new \RuntimeException(preg_last_error_msg());
+    }
+    return (bool) $result;
+  }
+
+  /**
+   * Determines if a test case is a deprecation test.
+   *
+   * Deprecation tests are those that are annotated with '@group legacy' or
+   * that have a '#[IgnoreDeprecations]' attribute.
+   *
+   * @param \PHPUnit\Framework\TestCase $testCase
+   *   The test case being executed.
+   */
+  public static function isDeprecationTest(TestCase $testCase): bool {
+    return $testCase->valueObjectForEvents()->metadata()->isIgnoreDeprecations()->isNotEmpty() || self::isTestInLegacyGroup($testCase);
+  }
+
+  /**
+   * Determines if a test case is part of the 'legacy' group.
+   *
+   * @param \PHPUnit\Framework\TestCase $testCase
+   *   The test case being executed.
+   */
+  private static function isTestInLegacyGroup(TestCase $testCase): bool {
+    $groups = [];
+    foreach ($testCase->valueObjectForEvents()->metadata()->isGroup() as $metadata) {
+      $groups[] = $metadata->groupName();
+    }
+    return in_array('legacy', $groups, TRUE);
+  }
+
+}
diff --git a/core/tests/Drupal/TestTools/Extension/DeprecationBridge/ExpectDeprecationTrait.php b/core/tests/Drupal/TestTools/Extension/DeprecationBridge/ExpectDeprecationTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..bd87d7db905e4b2c45e0975b6706ba80682c2996
--- /dev/null
+++ b/core/tests/Drupal/TestTools/Extension/DeprecationBridge/ExpectDeprecationTrait.php
@@ -0,0 +1,137 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\TestTools\Extension\DeprecationBridge;
+
+use Drupal\Core\Utility\Error;
+use Drupal\TestTools\ErrorHandler\TestErrorHandler;
+use PHPUnit\Framework\Attributes\After;
+use PHPUnit\Framework\Attributes\Before;
+
+/**
+ * A trait to include in Drupal tests to manage expected deprecations.
+ *
+ * This code works in coordination with DeprecationHandler.
+ *
+ * This trait is a replacement for symfony/phpunit-bridge that is not
+ * supporting PHPUnit 10. In the future this extension might be dropped if
+ * PHPUnit will support all deprecation management needs.
+ *
+ * @see \Drupal\TestTools\Extension\DeprecationBridge\DeprecationHandler
+ *
+ * @internal
+ */
+trait ExpectDeprecationTrait {
+
+  /**
+   * Sets up the test error handler.
+   *
+   * This method is run before each test's ::setUp() method, and when the
+   * DeprecationHandler is active, resets the extension to be able to collect
+   * the test's deprecations, and sets TestErrorHandler as the current error
+   * handler.
+   *
+   * @see \Drupal\TestTools\ErrorHandler\TestErrorHandler
+   */
+  #[Before]
+  public function setUpErrorHandler(): void {
+    if (!DeprecationHandler::isEnabled()) {
+      return;
+    }
+
+    DeprecationHandler::reset();
+    set_error_handler(new TestErrorHandler(Error::currentErrorHandler(), $this));
+  }
+
+  /**
+   * Tears down the test error handler.
+   *
+   * This method is run after each test's ::tearDown() method, and checks if
+   * collected deprecations match the expectations; it also resets the error
+   * handler to the one set prior of the change made by ::setUpErrorHandler().
+   */
+  #[After]
+  public function tearDownErrorHandler(): void {
+    if (!DeprecationHandler::isEnabled()) {
+      return;
+    }
+
+    // We expect that the current error handler is the one set by
+    // ::setUpErrorHandler() prior to the start of the test execution. If not,
+    // the error handler was changed during the test execution but not properly
+    // restored during ::tearDown().
+    $handler = Error::currentErrorHandler();
+    if (!$handler instanceof TestErrorHandler) {
+      throw new \RuntimeException(sprintf('%s registered its own error handler (%s) without restoring the previous one before or during tear down. This can cause unpredictable test results. Ensure the test cleans up after itself.',
+        $this->name(),
+        self::getCallableName($handler),
+      ));
+    }
+    restore_error_handler();
+
+    // Checks if collected deprecations match the expectations.
+    if (DeprecationHandler::getExpectedDeprecations()) {
+      $prefix = "@expectedDeprecation:\n";
+      $expDep = $prefix . '%A  ' . implode("\n%A  ", DeprecationHandler::getExpectedDeprecations()) . "\n%A";
+      $actDep = $prefix . '  ' . implode("\n  ", DeprecationHandler::getCollectedDeprecations()) . "\n";
+      $this->assertStringMatchesFormat($expDep, $actDep);
+    }
+  }
+
+  /**
+   * Adds an expected deprecation.
+   *
+   * @param string $message
+   *   The expected deprecation message.
+   */
+  public function expectDeprecation(string $message): void {
+    if (!DeprecationHandler::isDeprecationTest($this)) {
+      throw new \RuntimeException('expectDeprecation() can only be called from tests marked with #[IgnoreDeprecations] or \'@group legacy\'');
+    }
+
+    if (!DeprecationHandler::isEnabled()) {
+      return;
+    }
+
+    DeprecationHandler::expectDeprecation($message);
+  }
+
+  /**
+   * Returns a callable as a string suitable for inclusion in a message.
+   *
+   * @param callable $callable
+   *   The callable.
+   *
+   * @return string
+   *   The string suitable for inclusion in a message.
+   *
+   * @see https://stackoverflow.com/questions/34324576/print-name-or-definition-of-callable-in-php
+   */
+  private static function getCallableName(callable $callable): string {
+    switch (TRUE) {
+      case is_string($callable) && strpos($callable, '::'):
+        return '[static] ' . $callable;
+
+      case is_string($callable):
+        return '[function] ' . $callable;
+
+      case is_array($callable) && is_object($callable[0]):
+        return '[method] ' . get_class($callable[0]) . '->' . $callable[1];
+
+      case is_array($callable):
+        return '[static] ' . $callable[0] . '::' . $callable[1];
+
+      case $callable instanceof \Closure:
+        return '[closure]';
+
+      case is_object($callable):
+        return '[invokable] ' . get_class($callable);
+
+      default:
+        return '[unknown]';
+
+    }
+  }
+
+}
diff --git a/core/tests/Drupal/TestTools/Extension/HtmlLogging/HtmlOutputLogger.php b/core/tests/Drupal/TestTools/Extension/HtmlLogging/HtmlOutputLogger.php
new file mode 100644
index 0000000000000000000000000000000000000000..10a8f5a49b61f232b1731c3c822f911537853d63
--- /dev/null
+++ b/core/tests/Drupal/TestTools/Extension/HtmlLogging/HtmlOutputLogger.php
@@ -0,0 +1,143 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\TestTools\Extension\HtmlLogging;
+
+use PHPUnit\Event\Facade;
+use PHPUnit\Event\TestRunner\Finished as TestRunnerFinished;
+use PHPUnit\Event\TestRunner\Started as TestRunnerStarted;
+
+/**
+ * Drupal's extension for providing HTML output results for functional tests.
+ *
+ * @internal
+ */
+final class HtmlOutputLogger {
+
+  /**
+   * The singleton instance.
+   */
+  private static ?self $instance = NULL;
+
+  /**
+   * A file with list of links to HTML pages generated.
+   */
+  private ?string $browserOutputFile = NULL;
+
+  /**
+   * @throws \PHPUnit\Event\EventFacadeIsSealedException
+   * @throws \PHPUnit\Util\Exception
+   * @throws \PHPUnit\Event\UnknownSubscriberTypeException
+   * @throws \RuntimeException
+   */
+  private function __construct(
+    private readonly string $outputDirectory,
+    private readonly bool $outputVerbose,
+    private readonly Facade $facade,
+  ) {
+    $this->facade->registerSubscriber(new TestRunnerStartedSubscriber($this));
+    $this->facade->registerSubscriber(new TestRunnerFinishedSubscriber($this));
+  }
+
+  /**
+   * Initializes the extension.
+   *
+   * @param string $outputDirectory
+   *   The directory where the HTML pages should be generated.
+   * @param bool $outputVerbose
+   *   If TRUE, a list of links generated will be output at the end of the test
+   *   run; if FALSE, only a summary with the count of pages generated.
+   *
+   * @throws \PHPUnit\Event\EventFacadeIsSealedException
+   * @throws \PHPUnit\Util\Exception
+   * @throws \PHPUnit\Event\UnknownSubscriberTypeException
+   * @throws \RuntimeException
+   */
+  public static function init(string $outputDirectory, bool $outputVerbose): void {
+    if (self::$instance === NULL) {
+      $realDirectory = realpath($outputDirectory);
+      if ($realDirectory === FALSE || !is_dir($realDirectory) || !is_writable($realDirectory)) {
+        print "HTML output directory {$outputDirectory} is not a writable directory.\n\n";
+        return;
+      }
+      self::$instance = new self($realDirectory, $outputVerbose, Facade::instance());
+    }
+  }
+
+  /**
+   * Determines if the extension is enabled.
+   *
+   * @return bool
+   *   TRUE if enabled, FALSE if disabled.
+   */
+  public static function isEnabled(): bool {
+    return self::$instance !== NULL;
+  }
+
+  /**
+   * Logs a link to a generated HTML page.
+   *
+   * @param string $logEntry
+   *   A link to a generated HTML page.
+   *
+   * @throws \RuntimeException
+   */
+  public static function log(string $logEntry): void {
+    if (!self::isEnabled()) {
+      throw new \RuntimeException("HTML output is not enabled");
+    }
+
+    $browserOutputFile = getenv('BROWSERTEST_OUTPUT_FILE');
+    file_put_contents($browserOutputFile, $logEntry . "\n", FILE_APPEND);
+  }
+
+  /**
+   * Empties the list of the HTML output created during the test run.
+   */
+  public function testRunnerStarted(TestRunnerStarted $event): void {
+    if (!self::isEnabled()) {
+      throw new \RuntimeException("HTML output is not enabled");
+    }
+
+    // Convert to a canonicalized absolute pathname just in case the current
+    // working directory is changed.
+    $this->browserOutputFile = tempnam($this->outputDirectory, 'browser_output_');
+    if ($this->browserOutputFile) {
+      touch($this->browserOutputFile);
+      putenv('BROWSERTEST_OUTPUT_FILE=' . $this->browserOutputFile);
+    }
+    else {
+      // Remove any environment variable.
+      putenv('BROWSERTEST_OUTPUT_FILE');
+      throw new \RuntimeException("Unable to create a temporary file in {$this->outputDirectory}.");
+    }
+  }
+
+  /**
+   * Prints the list of HTML output generated during the test.
+   */
+  public function testRunnerFinished(TestRunnerFinished $event): void {
+    if (!self::isEnabled()) {
+      throw new \RuntimeException("HTML output is not enabled");
+    }
+
+    $contents = file_get_contents($this->browserOutputFile);
+    if ($contents) {
+      print "\n\n";
+      if ($this->outputVerbose) {
+        print "HTML output was generated.\n";
+        print $contents;
+      }
+      else {
+        print "HTML output was generated, " . count(explode("\n", $contents)) . " page(s).\n";
+      }
+    }
+
+    // No need to keep the file around any more.
+    unlink($this->browserOutputFile);
+    putenv('BROWSERTEST_OUTPUT_FILE');
+    $this->browserOutputFile = NULL;
+  }
+
+}
diff --git a/core/tests/Drupal/TestTools/Extension/HtmlLogging/SubscriberBase.php b/core/tests/Drupal/TestTools/Extension/HtmlLogging/SubscriberBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..9b562a79a855c919c76462c6992d137a2fd1b275
--- /dev/null
+++ b/core/tests/Drupal/TestTools/Extension/HtmlLogging/SubscriberBase.php
@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\TestTools\Extension\HtmlLogging;
+
+/**
+ * Base class for PHPUnit event subscribers related to HTML logging.
+ *
+ * @internal
+ */
+abstract class SubscriberBase {
+
+  public function __construct(
+    private readonly HtmlOutputLogger $logger,
+  ) {
+  }
+
+  protected function logger(): HtmlOutputLogger {
+    return $this->logger;
+  }
+
+}
diff --git a/core/tests/Drupal/TestTools/Extension/HtmlLogging/TestRunnerFinishedSubscriber.php b/core/tests/Drupal/TestTools/Extension/HtmlLogging/TestRunnerFinishedSubscriber.php
new file mode 100644
index 0000000000000000000000000000000000000000..806b24f72677a64dfb9e81eb37ea374c6b6a2195
--- /dev/null
+++ b/core/tests/Drupal/TestTools/Extension/HtmlLogging/TestRunnerFinishedSubscriber.php
@@ -0,0 +1,21 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\TestTools\Extension\HtmlLogging;
+
+use PHPUnit\Event\TestRunner\Finished;
+use PHPUnit\Event\TestRunner\FinishedSubscriber;
+
+/**
+ * Event subscriber notifying end of test runner execution to HTML logging.
+ *
+ * @internal
+ */
+final class TestRunnerFinishedSubscriber extends SubscriberBase implements FinishedSubscriber {
+
+  public function notify(Finished $event): void {
+    $this->logger()->testRunnerFinished($event);
+  }
+
+}
diff --git a/core/tests/Drupal/TestTools/Extension/HtmlLogging/TestRunnerStartedSubscriber.php b/core/tests/Drupal/TestTools/Extension/HtmlLogging/TestRunnerStartedSubscriber.php
new file mode 100644
index 0000000000000000000000000000000000000000..69d7056cbf332380ad22a649d619cd3d35efb660
--- /dev/null
+++ b/core/tests/Drupal/TestTools/Extension/HtmlLogging/TestRunnerStartedSubscriber.php
@@ -0,0 +1,21 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\TestTools\Extension\HtmlLogging;
+
+use PHPUnit\Event\TestRunner\Started;
+use PHPUnit\Event\TestRunner\StartedSubscriber;
+
+/**
+ * Event subscriber notifying beginning of test runner to HTML logging.
+ *
+ * @internal
+ */
+final class TestRunnerStartedSubscriber extends SubscriberBase implements StartedSubscriber {
+
+  public function notify(Started $event): void {
+    $this->logger()->testRunnerStarted($event);
+  }
+
+}
diff --git a/core/tests/Drupal/TestTools/PhpUnitCompatibility/ClassWriter.php b/core/tests/Drupal/TestTools/PhpUnitCompatibility/ClassWriter.php
deleted file mode 100644
index 76d5deb891db7c9c3e4a49286623f3683e46aefd..0000000000000000000000000000000000000000
--- a/core/tests/Drupal/TestTools/PhpUnitCompatibility/ClassWriter.php
+++ /dev/null
@@ -1,118 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\TestTools\PhpUnitCompatibility;
-
-use Composer\Autoload\ClassLoader;
-
-/**
- * Helper class to rewrite PHPUnit's TestCase class.
- *
- * This class contains static methods only and is not meant to be instantiated.
- *
- * @internal
- *   This should only be called by test running code. Drupal 9 will provide best
- *   effort to maintain this class for the Drupal 9 cycle. However if changes to
- *   PHP or PHPUnit make this impossible then support will be removed.
- */
-final class ClassWriter {
-
-  /**
-   * This class should not be instantiated.
-   */
-  private function __construct() {
-  }
-
-  /**
-   * Mutates PHPUnit classes to make it compatible with Drupal.
-   *
-   * @param \Composer\Autoload\ClassLoader $autoloader
-   *   The autoloader.
-   *
-   * @throws \ReflectionException
-   */
-  public static function mutateTestBase($autoloader) {
-    static::alterAssert($autoloader);
-    static::alterTestCase($autoloader);
-  }
-
-  /**
-   * Alters the Assert class.
-   *
-   * @param \Composer\Autoload\ClassLoader $autoloader
-   *   The autoloader.
-   *
-   * @throws \ReflectionException
-   */
-  private static function alterAssert(ClassLoader $autoloader): void {
-    // If the class exists already there is nothing we can do. Hopefully this
-    // is happening because this has been called already. The call from
-    // \Drupal\Core\Test\TestDiscovery::registerTestNamespaces() necessitates
-    // this protection.
-    if (class_exists('PHPUnit\Framework\Assert', FALSE)) {
-      return;
-    }
-    // Mutate Assert code to make it forward compatible with different PhpUnit
-    // versions, by adding Symfony's PHPUnit-bridge PolyfillAssertTrait.
-    $alteredFile = $autoloader->findFile('PHPUnit\Framework\Assert');
-    $phpunit_dir = dirname($alteredFile, 3);
-    $alteredCode = file_get_contents($alteredFile);
-    $alteredCode = preg_replace('/abstract class Assert[^\{]+\{/', '$0 ' . \PHP_EOL . "    use \Symfony\Bridge\PhpUnit\Legacy\PolyfillAssertTrait;" . \PHP_EOL, $alteredCode, 1);
-    include static::flushAlteredCodeToFile('Assert.php', $alteredCode);
-  }
-
-  /**
-   * Alters the TestCase class.
-   *
-   * @param \Composer\Autoload\ClassLoader $autoloader
-   *   The autoloader.
-   *
-   * @throws \ReflectionException
-   */
-  private static function alterTestCase(ClassLoader $autoloader): void {
-    // If the class exists already there is nothing we can do. Hopefully this
-    // is happening because this has been called already. The call from
-    // \Drupal\Core\Test\TestDiscovery::registerTestNamespaces() necessitates
-    // this protection.
-    if (class_exists('PHPUnit\Framework\TestCase', FALSE)) {
-      return;
-    }
-    // Mutate TestCase code to make it forward compatible with different PhpUnit
-    // versions, by adding Symfony's PHPUnit-bridge PolyfillTestCaseTrait.
-    $alteredFile = $autoloader->findFile('PHPUnit\Framework\TestCase');
-    $phpunit_dir = dirname($alteredFile, 3);
-    $alteredCode = file_get_contents($alteredFile);
-    $alteredCode = preg_replace('/abstract class TestCase[^\{]+\{/', '$0 ' . \PHP_EOL . "    use \Symfony\Bridge\PhpUnit\Legacy\PolyfillTestCaseTrait;" . \PHP_EOL, $alteredCode, 1);
-    $alteredCode = str_replace("__DIR__ . '/../Util/", "'$phpunit_dir/src/Util/", $alteredCode);
-    include static::flushAlteredCodeToFile('TestCase.php', $alteredCode);
-  }
-
-  /**
-   * Flushes altered class code to file when necessary.
-   *
-   * @param string $file_name
-   *   The file name.
-   * @param string $altered_code
-   *   The altered code.
-   *
-   * @return string
-   *   The full path of the file to be included.
-   */
-  private static function flushAlteredCodeToFile(string $file_name, string $altered_code): string {
-    $directory = __DIR__ . '/../../../../../sites/simpletest';
-    $full_path = $directory . '/' . $file_name;
-
-    // Only write when necessary.
-    if (!file_exists($full_path) || md5_file($full_path) !== md5($altered_code)) {
-      // Create directory when necessary.
-      if (!is_dir($directory) && !@mkdir($directory, 0777, TRUE) && !is_dir($directory)) {
-        throw new \RuntimeException('Unable to create directory: ' . $directory);
-      }
-      file_put_contents($full_path, $altered_code);
-    }
-
-    return $full_path;
-  }
-
-}
diff --git a/core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit9/TestCompatibilityTrait.php b/core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit10/TestCompatibilityTrait.php
similarity index 52%
rename from core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit9/TestCompatibilityTrait.php
rename to core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit10/TestCompatibilityTrait.php
index 06d874e2859bbfa44ad978a1af2a635b2ff5eeb0..a2dbea6ff52190bc293b06737cb1837258006b9c 100644
--- a/core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit9/TestCompatibilityTrait.php
+++ b/core/tests/Drupal/TestTools/PhpUnitCompatibility/PhpUnit10/TestCompatibilityTrait.php
@@ -2,22 +2,15 @@
 
 declare(strict_types=1);
 
-namespace Drupal\TestTools\PhpUnitCompatibility\PhpUnit9;
-
-use PHPUnit\Util\Test;
+namespace Drupal\TestTools\PhpUnitCompatibility\PhpUnit10;
 
 /**
  * Drupal's forward compatibility layer with multiple versions of PHPUnit.
+ *
+ * @internal
  */
 trait TestCompatibilityTrait {
 
-  /**
-   * Get test name.
-   */
-  public function name(): string {
-    return $this->getName();
-  }
-
   /**
    * Gets @covers defined on the test class.
    *
@@ -25,8 +18,11 @@ public function name(): string {
    *   An array of classes listed with the @covers annotation.
    */
   public function getTestClassCovers(): array {
-    $annotations = Test::parseTestMethodAnnotations(static::class, $this->name());
-    return $annotations['class']['covers'] ?? [];
+    $ret = [];
+    foreach ($this->valueObjectForEvents()->metadata()->isCovers()->isClassLevel() as $metadata) {
+      $ret[] = $metadata->target();
+    }
+    return $ret;
   }
 
 }
diff --git a/core/tests/Drupal/Tests/BrowserHtmlDebugTrait.php b/core/tests/Drupal/Tests/BrowserHtmlDebugTrait.php
index 0ce61082fd1809114316a1e5906b832a6d6c0d59..35400a5c90eb7e0efacb53697830f43478de0cc9 100644
--- a/core/tests/Drupal/Tests/BrowserHtmlDebugTrait.php
+++ b/core/tests/Drupal/Tests/BrowserHtmlDebugTrait.php
@@ -6,6 +6,7 @@
 
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Utility\Error;
+use Drupal\TestTools\Extension\HtmlLogging\HtmlOutputLogger;
 use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
 
@@ -49,17 +50,6 @@ trait BrowserHtmlDebugTrait {
    */
   protected $htmlOutputEnabled = FALSE;
 
-  /**
-   * The file name to write the list of URLs to.
-   *
-   * This file is read by the PHPUnit result printer.
-   *
-   * @var string
-   *
-   * @see \Drupal\Tests\Listeners\HtmlOutputPrinter
-   */
-  protected $htmlOutputFile;
-
   /**
    * HTML output test ID.
    *
@@ -128,21 +118,16 @@ protected function htmlOutput($message = NULL) {
     // Do not use the file_url_generator service as the module_handler service
     // might not be available.
     $uri = $this->htmlOutputBaseUrl . '/sites/simpletest/browser_output/' . $html_output_filename;
-    file_put_contents($this->htmlOutputFile, $uri . "\n", FILE_APPEND);
+    HtmlOutputLogger::log($uri . "\n");
   }
 
   /**
    * Creates the directory to store browser output.
-   *
-   * Creates the directory to store browser output in if a file to write
-   * URLs to has been created by \Drupal\Tests\Listeners\HtmlOutputPrinter.
    */
   protected function initBrowserOutputFile() {
-    $browser_output_file = getenv('BROWSERTEST_OUTPUT_FILE');
-    $this->htmlOutputEnabled = is_string($browser_output_file) && is_file($browser_output_file);
+    $this->htmlOutputEnabled = HtmlOutputLogger::isEnabled();
     $this->htmlOutputBaseUrl = getenv('BROWSERTEST_OUTPUT_BASE_URL') ?: $GLOBALS['base_url'];
     if ($this->htmlOutputEnabled) {
-      $this->htmlOutputFile = $browser_output_file;
       $this->htmlOutputClassName = str_replace("\\", "_", static::class);
       $this->htmlOutputDirectory = DRUPAL_ROOT . '/sites/simpletest/browser_output';
       // Do not use the file_system service so this method can be called before
diff --git a/core/tests/Drupal/Tests/BrowserTestBase.php b/core/tests/Drupal/Tests/BrowserTestBase.php
index f27fa37a40bd439b5c0f4e48478b6f35a1f3bb0c..83a1a0eb342f5a11d87c5dda7223a17179a9cbca 100644
--- a/core/tests/Drupal/Tests/BrowserTestBase.php
+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -6,6 +6,7 @@
 
 use Behat\Mink\Driver\BrowserKitDriver;
 use Behat\Mink\Element\Element;
+use Behat\Mink\Exception\Exception as MinkException;
 use Behat\Mink\Mink;
 use Behat\Mink\Selector\SelectorsHandler;
 use Behat\Mink\Session;
@@ -19,13 +20,12 @@
 use Drupal\Tests\block\Traits\BlockCreationTrait;
 use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
 use Drupal\Tests\node\Traits\NodeCreationTrait;
-use Drupal\Tests\Traits\PhpUnitWarnings;
 use Drupal\Tests\user\Traits\UserCreationTrait;
 use Drupal\TestTools\Comparator\MarkupInterfaceComparator;
+use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
 use Drupal\TestTools\TestVarDumper;
 use GuzzleHttp\Cookie\CookieJar;
 use PHPUnit\Framework\TestCase;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
 use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
 use Symfony\Component\VarDumper\VarDumper;
 
@@ -72,7 +72,6 @@ abstract class BrowserTestBase extends TestCase {
     createUser as drupalCreateUser;
   }
   use XdebugRequestTrait;
-  use PhpUnitWarnings;
   use PhpUnitCompatibilityTrait;
   use ExpectDeprecationTrait;
   use ExtensionListTestTrait;
@@ -173,19 +172,6 @@ abstract class BrowserTestBase extends TestCase {
    */
   protected $mink;
 
-  /**
-   * {@inheritdoc}
-   *
-   * Browser tests are run in separate processes to prevent collisions between
-   * code that may be loaded by tests.
-   */
-  protected $runTestInSeparateProcess = TRUE;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected $preserveGlobalState = FALSE;
-
   /**
    * The base URL.
    *
@@ -210,6 +196,14 @@ abstract class BrowserTestBase extends TestCase {
    */
   protected $originalContainer;
 
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(string $name) {
+    parent::__construct($name);
+    $this->setRunTestInSeparateProcess(TRUE);
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -369,7 +363,9 @@ protected function setUp(): void {
     $this->prepareEnvironment();
     $this->installDrupal();
 
-    // Setup Mink.
+    // Setup Mink. Register Mink exceptions to cause test failures instead of
+    // errors.
+    $this->registerFailureType(MinkException::class);
     $this->initMink();
 
     // Set up the browser test output file.
diff --git a/core/tests/Drupal/Tests/Component/Assertion/InspectorTest.php b/core/tests/Drupal/Tests/Component/Assertion/InspectorTest.php
index 1bdca0702e7135f3e3f1502b02d072c96782625b..a5e1c570516390e5911471019ea60a598b81e4da 100644
--- a/core/tests/Drupal/Tests/Component/Assertion/InspectorTest.php
+++ b/core/tests/Drupal/Tests/Component/Assertion/InspectorTest.php
@@ -6,7 +6,7 @@
 
 use PHPUnit\Framework\TestCase;
 use Drupal\Component\Assertion\Inspector;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
+use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
 
 /**
  * @coversDefaultClass \Drupal\Component\Assertion\Inspector
diff --git a/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php b/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php
index 7f1be690a8edc00497105582a9f9312a090aa500..0e42a0b4e8e5a8c9fb39e51aa9b1cf94ca038d6a 100644
--- a/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php
+++ b/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php
@@ -5,9 +5,9 @@
 namespace Drupal\Tests\Component\DependencyInjection;
 
 use Drupal\Component\Utility\Crypt;
+use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
 use PHPUnit\Framework\TestCase;
 use Prophecy\PhpUnit\ProphecyTrait;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
 use Symfony\Component\DependencyInjection\Exception\LogicException;
diff --git a/core/tests/Drupal/Tests/Component/DependencyInjection/Dumper/OptimizedPhpArrayDumperTest.php b/core/tests/Drupal/Tests/Component/DependencyInjection/Dumper/OptimizedPhpArrayDumperTest.php
index df31c85d8a6335735b5918b52a5a5736cdf04e6e..9766833a0a53edbe429acf272422833922e2ee7c 100644
--- a/core/tests/Drupal/Tests/Component/DependencyInjection/Dumper/OptimizedPhpArrayDumperTest.php
+++ b/core/tests/Drupal/Tests/Component/DependencyInjection/Dumper/OptimizedPhpArrayDumperTest.php
@@ -5,10 +5,10 @@
 namespace Drupal\Tests\Component\DependencyInjection\Dumper {
 
   use Drupal\Component\Utility\Crypt;
+  use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
   use PHPUnit\Framework\TestCase;
   use Prophecy\PhpUnit\ProphecyTrait;
   use Prophecy\Prophet;
-  use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
   use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
   use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
   use Symfony\Component\DependencyInjection\Definition;
diff --git a/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageReadOnlyTest.php b/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageReadOnlyTest.php
index 60fa0b4404093e471e9e2aa52ace4e36e8280f89..438814702c62e232a9965f5f2c9748f44de6a9c1 100644
--- a/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageReadOnlyTest.php
+++ b/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageReadOnlyTest.php
@@ -7,7 +7,7 @@
 use Drupal\Component\PhpStorage\FileStorage;
 use Drupal\Component\PhpStorage\FileReadOnlyStorage;
 use Drupal\Component\Utility\Random;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
+use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
 
 /**
  * @coversDefaultClass \Drupal\Component\PhpStorage\FileReadOnlyStorage
diff --git a/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageTest.php b/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageTest.php
index 19896437843d230568876904d7ef5474447c77f0..db63b5498b64cc840bdf940e7e2cea98d97cd238 100644
--- a/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageTest.php
+++ b/core/tests/Drupal/Tests/Component/PhpStorage/FileStorageTest.php
@@ -6,9 +6,8 @@
 
 use Drupal\Component\PhpStorage\FileStorage;
 use Drupal\Component\Utility\Random;
-use Drupal\Tests\Traits\PhpUnitWarnings;
+use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
 use org\bovigo\vfs\vfsStreamDirectory;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
 
 /**
  * @coversDefaultClass \Drupal\Component\PhpStorage\FileStorage
@@ -17,7 +16,7 @@
  */
 class FileStorageTest extends PhpStorageTestBase {
 
-  use PhpUnitWarnings, ExpectDeprecationTrait;
+  use ExpectDeprecationTrait;
 
   /**
    * Standard test settings to pass to storage instances.
diff --git a/core/tests/Drupal/Tests/Component/Render/FormattableMarkupTest.php b/core/tests/Drupal/Tests/Component/Render/FormattableMarkupTest.php
index cb52f2f6952418779cead52505d5680093904950..9bd02126d786e843de6432726a0413ede1b9462e 100644
--- a/core/tests/Drupal/Tests/Component/Render/FormattableMarkupTest.php
+++ b/core/tests/Drupal/Tests/Component/Render/FormattableMarkupTest.php
@@ -5,8 +5,8 @@
 namespace Drupal\Tests\Component\Render;
 
 use Drupal\Component\Render\FormattableMarkup;
+use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
 use PHPUnit\Framework\TestCase;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
 
 /**
  * Tests the TranslatableMarkup class.
diff --git a/core/tests/Drupal/Tests/Component/Utility/BytesTest.php b/core/tests/Drupal/Tests/Component/Utility/BytesTest.php
index e28b912fb5e203f20c422f85448ffba35effae92..04c77eb0a71b1de1afd1895cb895d79fa866694e 100644
--- a/core/tests/Drupal/Tests/Component/Utility/BytesTest.php
+++ b/core/tests/Drupal/Tests/Component/Utility/BytesTest.php
@@ -5,10 +5,10 @@
 namespace Drupal\Tests\Component\Utility;
 
 use Drupal\Component\Utility\Bytes;
+use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
 use PHPUnit\Framework\TestCase;
 use Prophecy\Argument;
 use Prophecy\PhpUnit\ProphecyTrait;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
 use Symfony\Component\Validator\Context\ExecutionContextInterface;
 
 /**
diff --git a/core/tests/Drupal/Tests/Component/Utility/UnicodeTest.php b/core/tests/Drupal/Tests/Component/Utility/UnicodeTest.php
index 6dfe031dd123e020f9c7e58b2feb5da485f856a4..291304532786fb49dd649ba3c644b5bddb7e7431 100644
--- a/core/tests/Drupal/Tests/Component/Utility/UnicodeTest.php
+++ b/core/tests/Drupal/Tests/Component/Utility/UnicodeTest.php
@@ -5,8 +5,8 @@
 namespace Drupal\Tests\Component\Utility;
 
 use Drupal\Component\Utility\Unicode;
+use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
 use PHPUnit\Framework\TestCase;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
 
 /**
  * Test unicode handling features implemented in Unicode component.
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/AssertUtilsTrait.php b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/AssertUtilsTrait.php
index a2257158b2c595a543a2a72788c0569c23075c03..9c5779f4604f86aa8f9a60a0e7918d4c6c89c6c0 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/AssertUtilsTrait.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/AssertUtilsTrait.php
@@ -4,13 +4,10 @@
 
 namespace Drupal\Tests\Composer\Plugin\Scaffold;
 
-use Drupal\Tests\Traits\PhpUnitWarnings;
-
 /**
  * Convenience class for creating fixtures.
  */
 trait AssertUtilsTrait {
-  use PhpUnitWarnings;
 
   /**
    * Asserts that a given file exists and is/is not a symlink.
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ManageGitIgnoreTest.php b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ManageGitIgnoreTest.php
index 3bea63641f30c987db3f01f60cf49a7c16889ade..e61a716ff8bf70ff9ac2921fd5cfce63c8cd35a3 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ManageGitIgnoreTest.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ManageGitIgnoreTest.php
@@ -8,7 +8,6 @@
 use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
 use Drupal\Tests\Composer\Plugin\Scaffold\AssertUtilsTrait;
 use Drupal\Tests\Composer\Plugin\Scaffold\ExecTrait;
-use Drupal\Tests\PhpUnitCompatibilityTrait;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -23,7 +22,6 @@
 class ManageGitIgnoreTest extends TestCase {
   use ExecTrait;
   use AssertUtilsTrait;
-  use PhpUnitCompatibilityTrait;
 
   /**
    * The root of this project.
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldTest.php b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldTest.php
index e5127780cb7054dfefe03a8bcc3206c28504fc87..012cc4590c4420a45b5297a3aa3774a96404682a 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldTest.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldTest.php
@@ -8,7 +8,6 @@
 use Drupal\Tests\Composer\Plugin\Scaffold\AssertUtilsTrait;
 use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
 use Drupal\Tests\Composer\Plugin\Scaffold\ScaffoldTestResult;
-use Drupal\Tests\PhpUnitCompatibilityTrait;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -21,7 +20,6 @@
  */
 class ScaffoldTest extends TestCase {
   use AssertUtilsTrait;
-  use PhpUnitCompatibilityTrait;
 
   /**
    * The root of this project.
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldUpgradeTest.php b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldUpgradeTest.php
index f28ec78ca510bcf7f8ead70ca4464270c83d95a7..c9f34d95516d1d592c724e2335bbebc76e63fed5 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldUpgradeTest.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldUpgradeTest.php
@@ -8,7 +8,6 @@
 use Drupal\Tests\Composer\Plugin\Scaffold\AssertUtilsTrait;
 use Drupal\Tests\Composer\Plugin\Scaffold\ExecTrait;
 use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
-use Drupal\Tests\PhpUnitCompatibilityTrait;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -28,7 +27,6 @@ class ScaffoldUpgradeTest extends TestCase {
 
   use AssertUtilsTrait;
   use ExecTrait;
-  use PhpUnitCompatibilityTrait;
 
   /**
    * The Fixtures object.
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/AppendOpTest.php b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/AppendOpTest.php
index 45806562416b4ef284fa647b00a6b6b86d763532..3cce05475a44ae84505132320d14294cdb464d75 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/AppendOpTest.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/AppendOpTest.php
@@ -7,7 +7,6 @@
 use Drupal\Composer\Plugin\Scaffold\Operations\AppendOp;
 use Drupal\Composer\Plugin\Scaffold\ScaffoldOptions;
 use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
-use Drupal\Tests\Traits\PhpUnitWarnings;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -16,7 +15,6 @@
  * @group Scaffold
  */
 class AppendOpTest extends TestCase {
-  use PhpUnitWarnings;
 
   /**
    * @covers ::process
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/ReplaceOpTest.php b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/ReplaceOpTest.php
index 00deb085684d63b5182a9064d229fa1eab99f89e..a781d5b9c66cc48ec48d6e3fcc055ddfcad57d5b 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/ReplaceOpTest.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/ReplaceOpTest.php
@@ -7,7 +7,6 @@
 use Drupal\Composer\Plugin\Scaffold\Operations\ReplaceOp;
 use Drupal\Composer\Plugin\Scaffold\ScaffoldOptions;
 use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
-use Drupal\Tests\Traits\PhpUnitWarnings;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -16,7 +15,6 @@
  * @group Scaffold
  */
 class ReplaceOpTest extends TestCase {
-  use PhpUnitWarnings;
 
   /**
    * @covers ::process
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/SkipOpTest.php b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/SkipOpTest.php
index 8fd239540bdecfbe8d7f84412f980589373b15de..5a13e34918a44621070aab64be45259fea65255f 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/SkipOpTest.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Integration/SkipOpTest.php
@@ -7,7 +7,6 @@
 use Drupal\Composer\Plugin\Scaffold\Operations\SkipOp;
 use Drupal\Composer\Plugin\Scaffold\ScaffoldOptions;
 use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
-use Drupal\Tests\Traits\PhpUnitWarnings;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -16,7 +15,6 @@
  * @group Scaffold
  */
 class SkipOpTest extends TestCase {
-  use PhpUnitWarnings;
 
   /**
    * @covers ::process
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/ConfigTest.php b/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/ConfigTest.php
index 442379723d3ddcb2d5635c454dfa7e34253b5d0c..66f28d2ed5e5ca86582fcda23e59c50107e4487a 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/ConfigTest.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/ConfigTest.php
@@ -6,7 +6,6 @@
 
 use Composer\Package\RootPackageInterface;
 use Drupal\Composer\Plugin\VendorHardening\Config;
-use Drupal\Tests\Traits\PhpUnitWarnings;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -15,8 +14,6 @@
  */
 class ConfigTest extends TestCase {
 
-  use PhpUnitWarnings;
-
   /**
    * @covers ::getPathsForPackage
    */
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/VendorHardeningPluginTest.php b/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/VendorHardeningPluginTest.php
index 1382235f77726767a4bdeeeb660492795455a69d..29c935fe1444545637aad629837038ba99983782 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/VendorHardeningPluginTest.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/VendorHardening/VendorHardeningPluginTest.php
@@ -10,7 +10,6 @@
 use Composer\Package\RootPackageInterface;
 use Drupal\Composer\Plugin\VendorHardening\Config;
 use Drupal\Composer\Plugin\VendorHardening\VendorHardeningPlugin;
-use Drupal\Tests\Traits\PhpUnitWarnings;
 use org\bovigo\vfs\vfsStream;
 use PHPUnit\Framework\TestCase;
 use Prophecy\PhpUnit\ProphecyTrait;
@@ -21,7 +20,6 @@
  */
 class VendorHardeningPluginTest extends TestCase {
 
-  use PhpUnitWarnings;
   use ProphecyTrait;
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Asset/CssOptimizerUnitTest.php b/core/tests/Drupal/Tests/Core/Asset/CssOptimizerUnitTest.php
index 2b7033ac8e13a1abbe660ba0ba085421819f91f6..985cc785f5918e1db5ed88768fc62670e3b5002f 100644
--- a/core/tests/Drupal/Tests/Core/Asset/CssOptimizerUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Asset/CssOptimizerUnitTest.php
@@ -15,11 +15,6 @@
  */
 class CssOptimizerUnitTest extends UnitTestCase {
 
-  /**
-   * {@inheritdoc}
-   */
-  protected $backupGlobals = FALSE;
-
   /**
    * A CSS asset optimizer.
    *
diff --git a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php
index 34e16dd5bae213750d2f6ebb567a123997869677..7e6590b797ded114a9c5714b644922b7dfdb3908 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php
@@ -67,7 +67,7 @@ public function testGetFormIdWithString() {
    * @covers ::getFormId
    */
   public function testGetFormIdWithNonFormClass() {
-    $form_arg = __CLASS__;
+    $form_arg = \stdClass::class;
     $form_state = new FormState();
     $this->expectException(\InvalidArgumentException::class);
     $this->expectExceptionMessage("The form argument $form_arg must be an instance of \Drupal\Core\Form\FormInterface.");
diff --git a/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php b/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php
index 8a532a4027f97013bcd68bf1cf0bac2626e54897..e83d5705c443b48a8517922c3b03d9dcaf0cc7a8 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php
@@ -84,16 +84,6 @@ class FormCacheTest extends UnitTestCase {
    */
   protected $requestPolicy;
 
-  /**
-   * {@inheritdoc}
-   */
-  protected $runTestInSeparateProcess = TRUE;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected $preserveGlobalState = FALSE;
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/tests/Drupal/Tests/Core/Form/FormStateDecoratorBaseTest.php b/core/tests/Drupal/Tests/Core/Form/FormStateDecoratorBaseTest.php
index 2b00dfdfa1a6e38d86c7870d62dacf77448232a8..3924855fd97d17966aece95d1a21c35fdb70b554 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormStateDecoratorBaseTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormStateDecoratorBaseTest.php
@@ -1451,7 +1451,7 @@ public static function providerPrepareCallback(): array {
     $closure = function () {};
     $static_method_string = __METHOD__;
     $static_method_array = [__CLASS__, __FUNCTION__];
-    $object_method_array = [new static(), __FUNCTION__];
+    $object_method_array = [new static('test'), __FUNCTION__];
 
     return [
       // A shorthand form method is generally expanded to become a method on an
diff --git a/core/tests/Drupal/Tests/Core/Security/RequestSanitizerTest.php b/core/tests/Drupal/Tests/Core/Security/RequestSanitizerTest.php
index 6e508a1ea62bff6427e3be5565620720a62cd59e..070f1d12631d886d45d025b61b25f14243e3c12a 100644
--- a/core/tests/Drupal/Tests/Core/Security/RequestSanitizerTest.php
+++ b/core/tests/Drupal/Tests/Core/Security/RequestSanitizerTest.php
@@ -34,6 +34,14 @@ protected function setUp(): void {
     set_error_handler([$this, "errorHandler"]);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown(): void {
+    restore_error_handler();
+    parent::tearDown();
+  }
+
   /**
    * Tests RequestSanitizer class.
    *
diff --git a/core/tests/Drupal/Tests/Core/StringTranslation/TranslatableMarkupTest.php b/core/tests/Drupal/Tests/Core/StringTranslation/TranslatableMarkupTest.php
index a9a1b363d27556369f32564f0244aa7c8f393f84..338c21a5c77abdd9a339e12995dee456983f716c 100644
--- a/core/tests/Drupal/Tests/Core/StringTranslation/TranslatableMarkupTest.php
+++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslatableMarkupTest.php
@@ -80,7 +80,7 @@ public function testToString() {
     restore_error_handler();
 
     $this->assertEquals(E_USER_ERROR, $this->lastErrorNumber);
-    $this->assertMatchesRegularExpression('/Exception thrown while calling __toString on a .*Mock_TranslatableMarkup_.* object in .*TranslatableMarkupTest.php on line [0-9]+: Yes you may./', $this->lastErrorMessage);
+    $this->assertMatchesRegularExpression('/Exception thrown while calling __toString on a .*MockObject_TranslatableMarkup_.* object in .*TranslatableMarkupTest.php on line [0-9]+: Yes you may./', $this->lastErrorMessage);
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Test/PhpUnitBridgeRequiresTest.php b/core/tests/Drupal/Tests/Core/Test/PhpUnitBridgeRequiresTest.php
deleted file mode 100644
index cf0e731ae8e1321e54541edd76a6149cf60e67c5..0000000000000000000000000000000000000000
--- a/core/tests/Drupal/Tests/Core/Test/PhpUnitBridgeRequiresTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\Core\Test;
-
-use Drupal\Tests\UnitTestCase;
-use Drupal\deprecation_test\Deprecation\FixtureDeprecatedClass;
-
-/**
- * Test how unit tests interact with deprecation errors.
- *
- * If a test requires an extension that does not exist and has a data provider
- * the interaction between Drupal and Symfony's deprecation testing can cause
- * errors. This test proves this is not broken.
- *
- * This test will be skipped and should not cause the test suite to fail.
- *
- * @group Test
- * @requires extension will_hopefully_never_exist
- * @see \Drupal\Tests\Listeners\DrupalListener
- */
-class PhpUnitBridgeRequiresTest extends UnitTestCase {
-
-  /**
-   * Tests the @requires annotation.
-   *
-   * @dataProvider providerTestWillNeverRun
-   */
-  public function testWillNeverRun(): void {
-    $deprecated = new FixtureDeprecatedClass();
-    $this->assertEquals('test', $deprecated->testFunction());
-  }
-
-  /**
-   * Data provider for ::testWillNeverRun().
-   */
-  public static function providerTestWillNeverRun(): array {
-    return [
-      ['this_will_never_run'],
-    ];
-  }
-
-}
diff --git a/core/tests/Drupal/Tests/Core/Test/PhpUnitBridgeTest.php b/core/tests/Drupal/Tests/Core/Test/PhpUnitBridgeTest.php
index fe3d5518261768ecfc62b041c68cd4c9924cc703..79420875f4e87937dc3a40cf1dd4cb48f035fa3a 100644
--- a/core/tests/Drupal/Tests/Core/Test/PhpUnitBridgeTest.php
+++ b/core/tests/Drupal/Tests/Core/Test/PhpUnitBridgeTest.php
@@ -29,18 +29,4 @@ public function testDeprecatedFunction() {
     $this->assertEquals('known_return_value', \deprecation_test_function());
   }
 
-  /**
-   * Tests the @requires annotation in conjunction with DrupalListener.
-   *
-   * This test method will be skipped and should not cause the test suite to
-   * fail.
-   *
-   * @requires extension will_hopefully_never_exist
-   * @see \Drupal\Tests\Listeners\DrupalListener
-   */
-  public function testWillNeverRun(): void {
-    $deprecated = new FixtureDeprecatedClass();
-    $this->assertEquals('test', $deprecated->testFunction());
-  }
-
 }
diff --git a/core/tests/Drupal/Tests/Core/Test/PhpUnitCliTest.php b/core/tests/Drupal/Tests/Core/Test/PhpUnitCliTest.php
index a240af9d4cbb7089ad26b31bfb1b2a46b8c42e4a..926a7cdedc5c006e3ce68fc0e3644ea3d3cd4265 100644
--- a/core/tests/Drupal/Tests/Core/Test/PhpUnitCliTest.php
+++ b/core/tests/Drupal/Tests/Core/Test/PhpUnitCliTest.php
@@ -5,7 +5,6 @@
 namespace Drupal\Tests\Core\Test;
 
 use Drupal\Tests\UnitTestCase;
-use Drupal\TestTools\PhpUnitCompatibility\RunnerVersion;
 use Symfony\Component\Process\Process;
 
 /**
@@ -31,11 +30,6 @@ public function testPhpUnitListTests() {
       '--list-tests',
     ];
 
-    // PHPUnit 10 dropped the --verbose command line option.
-    if (RunnerVersion::getMajor() < 10) {
-      $command[] = '--verbose';
-    }
-
     $process = new Process($command, $this->root);
     $process
       ->setTimeout(300)
diff --git a/core/tests/Drupal/Tests/Core/Test/PhpUnitTestRunnerTest.php b/core/tests/Drupal/Tests/Core/Test/PhpUnitTestRunnerTest.php
index 52c6e7980c29ead0666fda1bf067c4fa2363f7aa..c8dc2cd27b625f111f11c71b0399a107fd941481 100644
--- a/core/tests/Drupal/Tests/Core/Test/PhpUnitTestRunnerTest.php
+++ b/core/tests/Drupal/Tests/Core/Test/PhpUnitTestRunnerTest.php
@@ -53,7 +53,7 @@ public function testRunTestsError() {
     $runner->expects($this->once())
       ->method('runCommand')
       ->willReturnCallback(
-        function ($unescaped_test_classnames, $phpunit_file, &$status) {
+        function (string $test_class_name, string $log_junit_file_path, int &$status): string {
           $status = TestStatus::EXCEPTION;
           return ' ';
         }
@@ -63,7 +63,7 @@ function ($unescaped_test_classnames, $phpunit_file, &$status) {
     // to some value we don't expect back.
     $status = -1;
     $test_run = TestRun::createNew($storage);
-    $results = $runner->execute($test_run, ['SomeTest'], $status);
+    $results = $runner->execute($test_run, 'SomeTest', $status);
 
     // Make sure our status code made the round trip.
     $this->assertEquals(TestStatus::EXCEPTION, $status);
diff --git a/core/tests/Drupal/Tests/Core/Test/TestSuiteBaseTest.php b/core/tests/Drupal/Tests/Core/Test/TestSuiteBaseTest.php
index 1f53f981775e562bed4f5a4073bd641a569403b8..13fdffbb790650ecd277a4ce8b614b19300464e3 100644
--- a/core/tests/Drupal/Tests/Core/Test/TestSuiteBaseTest.php
+++ b/core/tests/Drupal/Tests/Core/Test/TestSuiteBaseTest.php
@@ -4,113 +4,13 @@
 
 namespace Drupal\Tests\Core\Test;
 
-use Drupal\Tests\TestSuites\TestSuiteBase;
-use org\bovigo\vfs\vfsStream;
 use PHPUnit\Framework\TestCase;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
-
-// The test suite class is not part of the autoloader, we need to include it
-// manually.
-require_once __DIR__ . '/../../../../TestSuites/TestSuiteBase.php';
 
 /**
- * @coversDefaultClass \Drupal\Tests\TestSuites\TestSuiteBase
- *
- * @group TestSuite
+ * @group Test
  */
 class TestSuiteBaseTest extends TestCase {
 
-  use ExpectDeprecationTrait;
-
-  /**
-   * Helper method to set up the file system.
-   *
-   * @return array[]
-   *   A Drupal filesystem suitable for use with vfsStream.
-   */
-  protected function getFilesystem() {
-    return [
-      'core' => [
-        'modules' => [],
-        'profiles' => [],
-        'tests' => [
-          'Drupal' => [
-            'NotUnitTests' => [
-              'CoreNotUnitTest.php' => '<?php',
-            ],
-            'Tests' => [
-              'CoreUnitTest.php' => '<?php',
-              // Ensure that the following files are not found as tests.
-              'Listeners' => [
-                'Listener.php' => '<?php',
-                'Legacy' => [
-                  'Listener.php' => '<?php',
-                ],
-              ],
-            ],
-          ],
-        ],
-      ],
-    ];
-  }
-
-  /**
-   * @return array[]
-   *   Test data for testAddTestsBySuiteNamespaceCore(). An array of arrays:
-   *   - A filesystem array for vfsStream.
-   *   - The sub-namespace of the test suite.
-   *   - The array of tests expected to be discovered.
-   */
-  public function provideCoreTests() {
-    $filesystem = $this->getFilesystem();
-    return [
-      'unit-tests' => [
-        $filesystem,
-        'Unit',
-        [
-          'Drupal\Tests\CoreUnitTest' => 'vfs://root/core/tests/Drupal/Tests/CoreUnitTest.php',
-        ],
-      ],
-      'not-unit-tests' => [
-        $filesystem,
-        'NotUnit',
-        [
-          'Drupal\NotUnitTests\CoreNotUnitTest' => 'vfs://root/core/tests/Drupal/NotUnitTests/CoreNotUnitTest.php',
-        ],
-      ],
-    ];
-  }
-
-  /**
-   * Tests for special case behavior of unit test suite namespaces in core.
-   *
-   * @group legacy
-   *
-   * @covers ::addTestsBySuiteNamespace
-   *
-   * @dataProvider provideCoreTests
-   */
-  public function testAddTestsBySuiteNamespaceCore($filesystem, $suite_namespace, $expected_tests) {
-
-    $this->expectDeprecation('Drupal\\Tests\\Core\\Test\\StubTestSuiteBase is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no replacement and test discovery will be handled differently in PHPUnit 10. See https://www.drupal.org/node/3405829');
-
-    // Set up the file system.
-    $vfs = vfsStream::setup('root');
-    vfsStream::create($filesystem, $vfs);
-
-    // Make a stub suite base to test.
-    $stub = new StubTestSuiteBase('test_me');
-
-    // Access addTestsBySuiteNamespace().
-    $ref_add_tests = new \ReflectionMethod($stub, 'addTestsBySuiteNamespace');
-
-    // Invoke addTestsBySuiteNamespace().
-    $ref_add_tests->invokeArgs($stub, [vfsStream::url('root'), $suite_namespace]);
-
-    // Determine if we loaded the expected test files.
-    $this->assertEquals($expected_tests, $stub->testFiles);
-  }
-
   /**
    * Tests the assumption that local time is in 'Australia/Sydney'.
    */
@@ -120,52 +20,3 @@ public function testLocalTimeZone() {
   }
 
 }
-
-/**
- * Stub subclass of TestSuiteBase.
- *
- * We use this class to alter the behavior of TestSuiteBase so it can be
- * testable.
- *
- * @phpstan-ignore-next-line
- */
-class StubTestSuiteBase extends TestSuiteBase {
-
-  /**
-   * Test files discovered by addTestsBySuiteNamespace().
-   *
-   * @var string[]
-   */
-  public $testFiles = [];
-
-  public function __construct(string $name) {
-    @trigger_error(__CLASS__ . ' is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no replacement and test discovery will be handled differently in PHPUnit 10. See https://www.drupal.org/node/3405829', E_USER_DEPRECATED);
-    // @phpstan-ignore-next-line
-    parent::__construct($name);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function findExtensionDirectories($root) {
-    // We have to stub findExtensionDirectories() because we can't inject a
-    // vfsStream filesystem into drupal_phpunit_find_extension_directories(),
-    // which uses \SplFileInfo->getRealPath(). getRealPath() resolves
-    // stream-based paths to an empty string. See
-    // https://github.com/mikey179/vfsStream/wiki/Known-Issues
-    return [];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addTestFiles($filenames): void {
-    // We stub addTestFiles() because the parent implementation can't deal with
-    // vfsStream-based filesystems due to an error in
-    // stream_resolve_include_path(). See
-    // https://github.com/mikey179/vfsStream/issues/5 Here we just store the
-    // test file being added in $this->testFiles.
-    $this->testFiles = array_merge($this->testFiles, $filenames);
-  }
-
-}
diff --git a/core/tests/Drupal/Tests/Core/Utility/CallableResolverTest.php b/core/tests/Drupal/Tests/Core/Utility/CallableResolverTest.php
index 89f7957d6a06c602905fd865c73397ed2f80b645..01bb1b9727241b5f3d7a6c9db4587f79f417a1cf 100644
--- a/core/tests/Drupal/Tests/Core/Utility/CallableResolverTest.php
+++ b/core/tests/Drupal/Tests/Core/Utility/CallableResolverTest.php
@@ -78,8 +78,8 @@ function ($suffix) {
         __CLASS__ . '::method',
       ],
       'Non-static function, instantiated by class resolver' => [
-        static::class . '::method',
-        __CLASS__ . '::method',
+        MethodCallable::class . '::method',
+        MethodCallable::class . '::method',
       ],
       'Non-static function, instantiated by class resolver, container injection' => [
         '\Drupal\Tests\Core\Utility\MockContainerInjection::getResult',
@@ -94,8 +94,8 @@ function ($suffix) {
         __CLASS__ . '::staticMethod',
       ],
       'Class with invoke method' => [
-        static::class,
-        __CLASS__ . '::__invoke',
+        MethodCallable::class,
+        MethodCallable::class . '::__invoke',
       ],
     ];
 
@@ -131,14 +131,14 @@ public static function callableResolverExceptionHandlingTestCases() {
         'The callable definition provided "[not_a_callable,not_a_callable]" is not a valid callable.',
       ],
       'Missing method on class, array notation' => [
-        [static::class, 'method_not_exists'],
+        [\stdClass::class, 'method_not_exists'],
         \InvalidArgumentException::class,
-        'The callable definition provided "[Drupal\Tests\Core\Utility\CallableResolverTest,method_not_exists]" is not a valid callable.',
+        'The callable definition provided "[stdClass,method_not_exists]" is not a valid callable.',
       ],
       'Missing method on class, static notation' => [
-        static::class . '::method_not_exists',
+        \stdClass::class . '::method_not_exists',
         \InvalidArgumentException::class,
-        'The callable definition provided was invalid. Either class "Drupal\Tests\Core\Utility\CallableResolverTest" does not have a method "method_not_exists", or it is not callable.',
+        'The callable definition provided was invalid. Either class "stdClass" does not have a method "method_not_exists", or it is not callable.',
       ],
       'Missing class, static notation' => [
         '\NotARealClass::method',
@@ -237,5 +237,38 @@ public static function staticMethod($suffix) {
 
 }
 
+class MethodCallable {
+
+  /**
+   * A test __invoke method.
+   *
+   * @param string $suffix
+   *   A suffix to append.
+   *
+   * @return string
+   *   A test string.
+   */
+  public function __invoke($suffix) {
+    return __METHOD__ . '+' . $suffix;
+  }
+
+  /**
+   * A test method that returns "foo".
+   *
+   * @param string $suffix
+   *   A suffix to append.
+   *
+   * @return string
+   *   A test string.
+   *
+   * @throws \Exception
+   *   Throws an exception when called statically.
+   */
+  public function method($suffix) {
+    return __METHOD__ . '+' . $suffix;
+  }
+
+}
+
 class NoMethodCallable {
 }
diff --git a/core/tests/Drupal/Tests/ExpectDeprecationTest.php b/core/tests/Drupal/Tests/ExpectDeprecationTest.php
index 8fc2b4c872a5e170bac05e9670b5281e0b9b4479..349a34f015f1fc8e3a4f37244f04df269c6b83db 100644
--- a/core/tests/Drupal/Tests/ExpectDeprecationTest.php
+++ b/core/tests/Drupal/Tests/ExpectDeprecationTest.php
@@ -4,8 +4,8 @@
 
 namespace Drupal\Tests;
 
+use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
 use PHPUnit\Framework\TestCase;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
 
 /**
  * Ensures Drupal has test coverage of Symfony's deprecation testing.
diff --git a/core/tests/Drupal/Tests/Listeners/DrupalListener.php b/core/tests/Drupal/Tests/Listeners/DrupalListener.php
deleted file mode 100644
index 26fa1e5001e364d7c14715c4b08537cd2e271f87..0000000000000000000000000000000000000000
--- a/core/tests/Drupal/Tests/Listeners/DrupalListener.php
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\Listeners;
-
-use PHPUnit\Framework\TestListener;
-use PHPUnit\Framework\TestListenerDefaultImplementation;
-use PHPUnit\Framework\Test;
-use PHPUnit\Framework\TestSuite;
-use Symfony\Bridge\PhpUnit\SymfonyTestsListener;
-
-/**
- * Listens to PHPUnit test runs.
- *
- * @internal
- */
-class DrupalListener implements TestListener {
-
-  use TestListenerDefaultImplementation;
-
-  /**
-   * The wrapped Symfony test listener.
-   *
-   * @var \Symfony\Bridge\PhpUnit\SymfonyTestsListener
-   */
-  private $symfonyListener;
-
-  /**
-   * Constructs the DrupalListener object.
-   */
-  public function __construct() {
-    $this->symfonyListener = new SymfonyTestsListener();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function startTestSuite(TestSuite $suite): void {
-    $this->symfonyListener->startTestSuite($suite);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addSkippedTest(Test $test, \Throwable $t, float $time): void {
-    $this->symfonyListener->addSkippedTest($test, $t, $time);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function startTest(Test $test): void {
-    $this->symfonyListener->startTest($test);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function endTest(Test $test, float $time): void {
-    $this->symfonyListener->endTest($test, $time);
-  }
-
-}
diff --git a/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php b/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php
deleted file mode 100644
index dcfd8e80e2ff5d422d225f7e1fd3e666578bfd96..0000000000000000000000000000000000000000
--- a/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinter.php
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\Listeners;
-
-use PHPUnit\Framework\TestResult;
-use PHPUnit\TextUI\DefaultResultPrinter;
-
-/**
- * Defines a class for providing html output results for functional tests.
- *
- * @internal
- */
-class HtmlOutputPrinter extends DefaultResultPrinter {
-
-  use HtmlOutputPrinterTrait;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function printResult(TestResult $result): void {
-    parent::printResult($result);
-
-    $this->printHtmlOutput();
-  }
-
-}
diff --git a/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinterTrait.php b/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinterTrait.php
deleted file mode 100644
index 33507046884a6a6f93e279e9acaecb152bec95ed..0000000000000000000000000000000000000000
--- a/core/tests/Drupal/Tests/Listeners/HtmlOutputPrinterTrait.php
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\Listeners;
-
-/**
- * Defines a class for providing html output results for functional tests.
- *
- * @internal
- */
-trait HtmlOutputPrinterTrait {
-
-  /**
-   * File to write html links to.
-   *
-   * @var string
-   */
-  protected $browserOutputFile;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function __construct($out = NULL, $verbose = FALSE, $colors = self::COLOR_DEFAULT, $debug = FALSE, $numberOfColumns = 80, $reverse = FALSE) {
-    parent::__construct($out, $verbose, $colors, $debug, $numberOfColumns, $reverse);
-
-    $this->setUpHtmlOutput();
-  }
-
-  /**
-   * Creates the file to list the HTML output created during the test.
-   *
-   * @see \Drupal\Tests\BrowserTestBase::initBrowserOutputFile()
-   */
-  protected function setUpHtmlOutput() {
-    if ($html_output_directory = getenv('BROWSERTEST_OUTPUT_DIRECTORY')) {
-      // Initialize html output debugging.
-      $html_output_directory = rtrim($html_output_directory, '/');
-
-      // Check if directory exists.
-      if (!is_dir($html_output_directory) || !is_writable($html_output_directory)) {
-        $this->writeWithColor('bg-red, fg-black', "HTML output directory $html_output_directory is not a writable directory.");
-      }
-      else {
-        // Convert to a canonicalized absolute pathname just in case the current
-        // working directory is changed.
-        $html_output_directory = realpath($html_output_directory);
-        $this->browserOutputFile = tempnam($html_output_directory, 'browser_output_');
-        if ($this->browserOutputFile) {
-          touch($this->browserOutputFile);
-        }
-        else {
-          $this->writeWithColor('bg-red, fg-black', "Unable to create a temporary file in $html_output_directory.");
-        }
-      }
-    }
-
-    if ($this->browserOutputFile) {
-      putenv('BROWSERTEST_OUTPUT_FILE=' . $this->browserOutputFile);
-    }
-    else {
-      // Remove any environment variable.
-      putenv('BROWSERTEST_OUTPUT_FILE');
-    }
-  }
-
-  /**
-   * Prints the list of HTML output generated during the test.
-   */
-  protected function printHtmlOutput() {
-    if ($this->browserOutputFile) {
-      $contents = file_get_contents($this->browserOutputFile);
-      if ($contents) {
-        $this->writeNewLine();
-        $this->writeWithColor('bg-yellow, fg-black', 'HTML output was generated');
-        $this->write($contents);
-      }
-      // No need to keep the file around any more.
-      unlink($this->browserOutputFile);
-    }
-  }
-
-}
diff --git a/core/tests/Drupal/Tests/PhpUnitCompatibilityTrait.php b/core/tests/Drupal/Tests/PhpUnitCompatibilityTrait.php
index 932bd03a3e83aa8b70e03d0d1954051bd549bb23..57885d9205724233f6ebcd1eb5e9c29b1a0d54ac 100644
--- a/core/tests/Drupal/Tests/PhpUnitCompatibilityTrait.php
+++ b/core/tests/Drupal/Tests/PhpUnitCompatibilityTrait.php
@@ -22,7 +22,7 @@ class_alias("Drupal\TestTools\PhpUnitCompatibility\PhpUnit" . RunnerVersion::get
    */
   trait PhpUnitCompatibilityTrait {
 
-    use \Drupal\TestTools\PhpUnitCompatibility\PhpUnit9\TestCompatibilityTrait;
+    use \Drupal\TestTools\PhpUnitCompatibility\PhpUnit10\TestCompatibilityTrait;
 
   }
 
diff --git a/core/tests/Drupal/Tests/PhpUnitWarningsTest.php b/core/tests/Drupal/Tests/PhpUnitWarningsTest.php
deleted file mode 100644
index 67d632928fb18ef204aad244088779c02ac71236..0000000000000000000000000000000000000000
--- a/core/tests/Drupal/Tests/PhpUnitWarningsTest.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests;
-
-/**
- * @coversDefaultClass \Drupal\Tests\Traits\PhpUnitWarnings
- * @group legacy
- */
-class PhpUnitWarningsTest extends UnitTestCase {
-
-  /**
-   * Tests that selected PHPUnit warning is converted to deprecation.
-   */
-  public function testAddWarning() {
-    $this->expectDeprecation('Test warning for \Drupal\Tests\PhpUnitWarningsTest::testAddWarning()');
-    $this->addWarning('Test warning for \Drupal\Tests\PhpUnitWarningsTest::testAddWarning()');
-  }
-
-}
diff --git a/core/tests/Drupal/Tests/Traits/PhpUnitWarnings.php b/core/tests/Drupal/Tests/Traits/PhpUnitWarnings.php
deleted file mode 100644
index 180179a8a67a615bb13edc3df34ffdb6be71f0c5..0000000000000000000000000000000000000000
--- a/core/tests/Drupal/Tests/Traits/PhpUnitWarnings.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\Traits;
-
-/**
- * Converts deprecation warnings added by PHPUnit to silenced deprecations.
- *
- * This trait exists to allow Drupal to run tests with multiple versions of
- * PHPUnit without failing due to PHPUnit's deprecation warnings.
- *
- * @internal
- */
-trait PhpUnitWarnings {
-
-  /**
-   * Deprecation warnings from PHPUnit to raise with @trigger_error().
-   *
-   * Add any PHPUnit deprecations that should be handled as deprecation warnings
-   * (rather than unconditional failures) for core and contrib.
-   *
-   * @var string[]
-   */
-  private static $deprecationWarnings = [
-    // Warning for testing.
-    'Test warning for \Drupal\Tests\PhpUnitWarningsTest::testAddWarning()',
-    // PHPUnit 9.
-    'assertFileNotExists() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertFileDoesNotExist() instead.',
-    'assertRegExp() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertMatchesRegularExpression() instead.',
-    'assertNotRegExp() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDoesNotMatchRegularExpression() instead.',
-    'assertDirectoryNotExists() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDirectoryDoesNotExist() instead.',
-    'Support for using expectException() with PHPUnit\\Framework\\Error\\Warning is deprecated and will be removed in PHPUnit 10. Use expectWarning() instead.',
-    'Support for using expectException() with PHPUnit\\Framework\\Error\\Error is deprecated and will be removed in PHPUnit 10. Use expectError() instead.',
-    'assertDirectoryNotIsWritable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertDirectoryIsNotWritable() instead.',
-    'assertFileNotIsWritable() is deprecated and will be removed in PHPUnit 10. Refactor your code to use assertFileIsNotWritable() instead.',
-    // cspell:disable-next-line
-    'The at() matcher has been deprecated. It will be removed in PHPUnit 10. Please refactor your test to not rely on the order in which methods are invoked.',
-    // PHPUnit 9.6.
-    'Expecting E_WARNING and E_USER_WARNING is deprecated and will no longer be possible in PHPUnit 10.',
-    'Expecting E_ERROR and E_USER_ERROR is deprecated and will no longer be possible in PHPUnit 10.',
-    'assertObjectHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectHasProperty() instead.',
-    'assertObjectNotHasAttribute() is deprecated and will be removed in PHPUnit 10. Refactor your test to use assertObjectNotHasProperty() instead.',
-  ];
-
-  /**
-   * Converts PHPUnit deprecation warnings to E_USER_DEPRECATED.
-   *
-   * @param string $warning
-   *   The warning message raised in tests.
-   *
-   * @see \PHPUnit\Framework\TestCase::addWarning()
-   *
-   * @internal
-   */
-  public function addWarning(string $warning): void {
-    if (in_array($warning, self::$deprecationWarnings, TRUE)) {
-      // Convert listed PHPUnit deprecations into E_USER_DEPRECATED and prevent
-      // each from being raised as a test warning.
-      @trigger_error($warning, E_USER_DEPRECATED);
-      return;
-    }
-
-    // Otherwise, let the parent raise any warning not specifically listed.
-    parent::addWarning($warning);
-  }
-
-}
diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php
index 2ca419d204bea7211bf2b6b142f33ea3477ca573..6bff44c0854449fbb43abe9e7aeac095ad073800 100644
--- a/core/tests/Drupal/Tests/UnitTestCase.php
+++ b/core/tests/Drupal/Tests/UnitTestCase.php
@@ -10,12 +10,11 @@
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
-use Drupal\Tests\Traits\PhpUnitWarnings;
+use Drupal\TestTools\Extension\DeprecationBridge\ExpectDeprecationTrait;
 use Drupal\TestTools\TestVarDumper;
 use PHPUnit\Framework\TestCase;
 use Prophecy\PhpUnit\ProphecyTrait;
 use Symfony\Component\VarDumper\VarDumper;
-use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
 
 /**
  * Provides a base class and helpers for Drupal unit tests.
@@ -27,7 +26,6 @@
  */
 abstract class UnitTestCase extends TestCase {
 
-  use PhpUnitWarnings;
   use PhpUnitCompatibilityTrait;
   use ProphecyTrait;
   use ExpectDeprecationTrait;
diff --git a/core/tests/TestSuites/BuildTestSuite.php b/core/tests/TestSuites/BuildTestSuite.php
deleted file mode 100644
index c26bf44e59f1b28d51804543bdb1cf0b0f2afbaa..0000000000000000000000000000000000000000
--- a/core/tests/TestSuites/BuildTestSuite.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\TestSuites;
-
-require_once __DIR__ . '/TestSuiteBase.php';
-
-/**
- * Discovers tests for the build test suite.
- *
- * @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no
- *   replacement and test discovery will be handled differently in PHPUnit 10.
- *
- * @see https://www.drupal.org/node/3405829
- */
-class BuildTestSuite extends TestSuiteBase {
-
-  /**
-   * Factory method which loads up a suite with all build tests.
-   *
-   * @return static
-   *   The test suite.
-   */
-  public static function suite() {
-    $root = dirname(__DIR__, 3);
-
-    $suite = new static('build');
-    $suite->addTestsBySuiteNamespace($root, 'Build');
-
-    return $suite;
-  }
-
-}
diff --git a/core/tests/TestSuites/FunctionalJavascriptTestSuite.php b/core/tests/TestSuites/FunctionalJavascriptTestSuite.php
deleted file mode 100644
index 5ae2325121b9e8d865b00ac58340bd6862697b3d..0000000000000000000000000000000000000000
--- a/core/tests/TestSuites/FunctionalJavascriptTestSuite.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\TestSuites;
-
-require_once __DIR__ . '/TestSuiteBase.php';
-
-/**
- * Discovers tests for the functional-javascript test suite.
- *
- * @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no
- *   replacement and test discovery will be handled differently in PHPUnit 10.
- *
- * @see https://www.drupal.org/node/3405829
- */
-class FunctionalJavascriptTestSuite extends TestSuiteBase {
-
-  /**
-   * Factory method which loads up a suite with all functional javascript tests.
-   *
-   * @return static
-   *   The test suite.
-   */
-  public static function suite() {
-    $root = dirname(__DIR__, 3);
-
-    $suite = new static('functional-javascript');
-    $suite->addTestsBySuiteNamespace($root, 'FunctionalJavascript');
-
-    return $suite;
-  }
-
-}
diff --git a/core/tests/TestSuites/FunctionalTestSuite.php b/core/tests/TestSuites/FunctionalTestSuite.php
deleted file mode 100644
index 20aed98deec65ed359b18248ef0f867bd635a272..0000000000000000000000000000000000000000
--- a/core/tests/TestSuites/FunctionalTestSuite.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\TestSuites;
-
-require_once __DIR__ . '/TestSuiteBase.php';
-
-/**
- * Discovers tests for the functional test suite.
- *
- * @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no
- *   replacement and test discovery will be handled differently in PHPUnit 10.
- *
- * @see https://www.drupal.org/node/3405829
- */
-class FunctionalTestSuite extends TestSuiteBase {
-
-  /**
-   * Factory method which loads up a suite with all functional tests.
-   *
-   * @return static
-   *   The test suite.
-   */
-  public static function suite() {
-    $root = dirname(__DIR__, 3);
-
-    $suite = new static('functional');
-    $suite->addTestsBySuiteNamespace($root, 'Functional');
-
-    return $suite;
-  }
-
-}
diff --git a/core/tests/TestSuites/KernelTestSuite.php b/core/tests/TestSuites/KernelTestSuite.php
deleted file mode 100644
index 0916c8528facb8d4b89dcadeca3835e4888a7c2b..0000000000000000000000000000000000000000
--- a/core/tests/TestSuites/KernelTestSuite.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\TestSuites;
-
-require_once __DIR__ . '/TestSuiteBase.php';
-
-/**
- * Discovers tests for the kernel test suite.
- *
- * @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no
- *   replacement and test discovery will be handled differently in PHPUnit 10.
- *
- * @see https://www.drupal.org/node/3405829
- */
-class KernelTestSuite extends TestSuiteBase {
-
-  /**
-   * Factory method which loads up a suite with all kernel tests.
-   *
-   * @return static
-   *   The test suite.
-   */
-  public static function suite() {
-    $root = dirname(__DIR__, 3);
-
-    $suite = new static('kernel');
-    $suite->addTestsBySuiteNamespace($root, 'Kernel');
-
-    return $suite;
-  }
-
-}
diff --git a/core/tests/TestSuites/TestSuiteBase.php b/core/tests/TestSuites/TestSuiteBase.php
deleted file mode 100644
index 435116d86584fc5f5616589d5a94bde4c2fcea21..0000000000000000000000000000000000000000
--- a/core/tests/TestSuites/TestSuiteBase.php
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\TestSuites;
-
-use Drupal\Core\Test\TestDiscovery;
-use PHPUnit\Framework\TestSuite;
-
-/**
- * Base class for Drupal test suites.
- *
- * @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no
- *   replacement and test discovery will be handled differently in PHPUnit 10.
- *
- * @see https://www.drupal.org/node/3405829
- */
-abstract class TestSuiteBase extends TestSuite {
-
-  /**
-   * Finds extensions in a Drupal installation.
-   *
-   * An extension is defined as a directory with an *.info.yml file in it.
-   *
-   * @param string $root
-   *   Path to the root of the Drupal installation.
-   *
-   * @return string[]
-   *   Associative array of extension paths, with extension name as keys.
-   */
-  protected function findExtensionDirectories($root) {
-    $extension_roots = \drupal_phpunit_contrib_extension_directory_roots($root);
-
-    $extension_directories = array_map('drupal_phpunit_find_extension_directories', $extension_roots);
-    return array_reduce($extension_directories, 'array_merge', []);
-  }
-
-  /**
-   * Find and add tests to the suite for core and any extensions.
-   *
-   * @param string $root
-   *   Path to the root of the Drupal installation.
-   * @param string $suite_namespace
-   *   SubNamespace used to separate test suite. Examples: Unit, Functional.
-   */
-  protected function addTestsBySuiteNamespace($root, $suite_namespace) {
-    // Core's tests are in the namespace Drupal\{$suite_namespace}Tests\ and are
-    // always inside of core/tests/Drupal/{$suite_namespace}Tests. The exception
-    // to this is Unit tests for historical reasons.
-    if ($suite_namespace == 'Unit') {
-      $tests = TestDiscovery::scanDirectory("Drupal\\Tests\\", "$root/core/tests/Drupal/Tests");
-      $tests = array_flip(array_filter(array_flip($tests), function ($test_class) {
-        // The Listeners directory does not contain tests. Use the class name
-        // to be compatible with all operating systems.
-        return !preg_match('/^Drupal\\\\Tests\\\\Listeners\\\\/', $test_class);
-      }));
-      $this->addTestFiles($tests);
-    }
-    else {
-      $this->addTestFiles(TestDiscovery::scanDirectory("Drupal\\{$suite_namespace}Tests\\", "$root/core/tests/Drupal/{$suite_namespace}Tests"));
-    }
-
-    // Extensions' tests will always be in the namespace
-    // Drupal\Tests\$extension_name\$suite_namespace\ and be in the
-    // $extension_path/tests/src/$suite_namespace directory. Not all extensions
-    // will have all kinds of tests.
-    foreach ($this->findExtensionDirectories($root) as $extension_name => $dir) {
-      $test_path = "$dir/tests/src/$suite_namespace";
-      if (is_dir($test_path)) {
-        $this->addTestFiles(TestDiscovery::scanDirectory("Drupal\\Tests\\$extension_name\\$suite_namespace\\", $test_path));
-      }
-    }
-  }
-
-}
diff --git a/core/tests/TestSuites/UnitTestSuite.php b/core/tests/TestSuites/UnitTestSuite.php
deleted file mode 100644
index db779652db46c86ab6a67e016affc936e12b4961..0000000000000000000000000000000000000000
--- a/core/tests/TestSuites/UnitTestSuite.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\Tests\TestSuites;
-
-require_once __DIR__ . '/TestSuiteBase.php';
-
-/**
- * Discovers tests for the unit test suite.
- *
- * @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. There is no
- *   replacement and test discovery will be handled differently in PHPUnit 10.
- *
- * @see https://www.drupal.org/node/3405829
- */
-class UnitTestSuite extends TestSuiteBase {
-
-  /**
-   * Factory method which loads up a suite with all unit tests.
-   *
-   * @return static
-   *   The test suite.
-   */
-  public static function suite() {
-    $root = dirname(__DIR__, 3);
-
-    $suite = new static('unit');
-    $suite->addTestsBySuiteNamespace($root, 'Unit');
-
-    return $suite;
-  }
-
-}
diff --git a/core/tests/bootstrap.php b/core/tests/bootstrap.php
index 05479c1d0e58469714fe7b63e70557555053ed70..56f7cd68a2477b7b8e359bf8a9d4b2b0b7131067 100644
--- a/core/tests/bootstrap.php
+++ b/core/tests/bootstrap.php
@@ -7,7 +7,11 @@
  * @see phpunit.xml.dist
  */
 
-use Drupal\TestTools\PhpUnitCompatibility\ClassWriter;
+use Drupal\TestTools\ErrorHandler\BootstrapErrorHandler;
+use Drupal\TestTools\Extension\DeprecationBridge\DeprecationHandler;
+use Drupal\TestTools\Extension\HtmlLogging\HtmlOutputLogger;
+use PHPUnit\Runner\ErrorHandler as PhpUnitErrorHandler;
+use Symfony\Component\ErrorHandler\DebugClassLoader;
 
 /**
  * Finds all valid extension directories recursively within a given directory.
@@ -142,8 +146,6 @@ function drupal_phpunit_populate_class_loader() {
 $loader = drupal_phpunit_populate_class_loader();
 class_alias('\Drupal\Tests\DocumentElement', '\Behat\Mink\Element\DocumentElement', TRUE);
 
-ClassWriter::mutateTestBase($loader);
-
 // Set sane locale settings, to ensure consistent string, dates, times and
 // numbers handling.
 // @see \Drupal\Core\DrupalKernel::bootEnvironment()
@@ -160,11 +162,26 @@ class_alias('\Drupal\Tests\DocumentElement', '\Behat\Mink\Element\DocumentElemen
 // reduce the fragility of the testing system in general.
 date_default_timezone_set('Australia/Sydney');
 
-// Ensure ignored deprecation patterns listed in .deprecation-ignore.txt are
-// considered in testing.
-if (getenv('SYMFONY_DEPRECATIONS_HELPER') === FALSE) {
-  $deprecation_ignore_filename = realpath(__DIR__ . "/../.deprecation-ignore.txt");
-  putenv("SYMFONY_DEPRECATIONS_HELPER=ignoreFile=$deprecation_ignore_filename");
+// Bootstrap the DeprecationHandler extension and the DebugClassloader to report
+// deprecations in PHPUnit 10+.
+if ($deprecationBridgeConfiguration = DeprecationHandler::getConfiguration()) {
+  DeprecationHandler::init($deprecationBridgeConfiguration['ignoreFile'] ?? NULL);
+
+  // Need to have an early error handler to manage deprecations triggered by
+  // DebugClassLoader, that occur before tests' setUp() methods are called.
+  // We pass an instance of the PHPUnit error handler to redirect any error not
+  // managed by our layer back to PHPUnit.
+  set_error_handler(new BootstrapErrorHandler(new PhpUnitErrorHandler()));
+
+  // Enable the DebugClassLoader to get deprecations for methods' signature
+  // changes.
+  DebugClassLoader::enable();
+}
+
+// Functional tests HTML output logging.
+$browserTestOutputDirectory = getenv('BROWSERTEST_OUTPUT_DIRECTORY');
+if ($browserTestOutputDirectory !== FALSE) {
+  HtmlOutputLogger::init($browserTestOutputDirectory, (bool) getenv('BROWSERTEST_OUTPUT_VERBOSE') ?? FALSE);
 }
 
 // Drupal expects to be run from its root directory. This ensures all test types