From c9dd05cfecc43af220a6d844885d28a8c70d90a2 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 20 Aug 2026 08:23:45 +0400 Subject: [PATCH 1/3] Tests: Isolate REST block type fixtures --- .../rest-api/rest-block-type-controller.php | 68 ++++++++++++++++--- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/tests/phpunit/tests/rest-api/rest-block-type-controller.php b/tests/phpunit/tests/rest-api/rest-block-type-controller.php index 3cf8c5244d77c..bdf433436e086 100644 --- a/tests/phpunit/tests/rest-api/rest-block-type-controller.php +++ b/tests/phpunit/tests/rest-api/rest-block-type-controller.php @@ -31,6 +31,20 @@ class REST_Block_Type_Controller_Test extends WP_Test_REST_Controller_Testcase { */ protected static $subscriber_id; + /** + * Pre-existing block types registered before the current test. + * + * @var string[] $registered_block_types + */ + private $registered_block_types = array(); + + /** + * Pre-existing block styles registered before the current test, grouped by block type name. + * + * @var array[] $registered_block_styles + */ + private $registered_block_styles = array(); + /** * Create fake data before our tests run. * @@ -49,21 +63,55 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { 'role' => 'subscriber', ) ); - - $name = 'fake/test'; - $settings = array( - 'icon' => 'text', - ); - - register_block_type( $name, $settings ); } public static function wpTearDownAfterClass() { self::delete_user( self::$admin_id ); self::delete_user( self::$subscriber_id ); - unregister_block_type( 'fake/test' ); - unregister_block_type( 'fake/invalid' ); - unregister_block_type( 'fake/false' ); + } + + /** + * Sets up each test method. + * + * Records the registered block types and block styles so that anything + * registered by a test can be unregistered again in tear_down(), and + * registers a block type used by many tests in this class. + */ + public function set_up() { + parent::set_up(); + + $this->registered_block_types = array_keys( WP_Block_Type_Registry::get_instance()->get_all_registered() ); + $this->registered_block_styles = WP_Block_Styles_Registry::get_instance()->get_all_registered(); + + register_block_type( + 'fake/test', + array( + 'icon' => 'text', + ) + ); + } + + /** + * Tears down each test method. + * + * Unregisters any block types and block styles registered while the test ran. + */ + public function tear_down() { + foreach ( WP_Block_Styles_Registry::get_instance()->get_all_registered() as $block_name => $block_styles ) { + foreach ( array_keys( $block_styles ) as $block_style_name ) { + if ( ! isset( $this->registered_block_styles[ $block_name ][ $block_style_name ] ) ) { + unregister_block_style( $block_name, $block_style_name ); + } + } + } + + foreach ( array_keys( WP_Block_Type_Registry::get_instance()->get_all_registered() ) as $block_name ) { + if ( ! in_array( $block_name, $this->registered_block_types, true ) ) { + unregister_block_type( $block_name ); + } + } + + parent::tear_down(); } /** From 002299c3e39a9feb0bc0b3edc73becc994567653 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 19 Aug 2026 22:40:56 +0400 Subject: [PATCH 2/3] Tests: Improve REST API test isolation --- tests/phpunit/tests/oembed/controller.php | 4 ++- .../rest-api/rest-attachments-controller.php | 8 +++++ tests/phpunit/tests/rest-api/rest-server.php | 1 + .../rest-api/rest-sidebars-controller.php | 31 ++++++++++++++----- .../tests/rest-api/rest-themes-controller.php | 26 +++++++++++++++- .../rest-api/rest-widget-types-controller.php | 16 +++++++++- .../rest-api/rest-widgets-controller.php | 5 +++ .../rest-api/wpRestUrlDetailsController.php | 8 +++++ 8 files changed, 88 insertions(+), 11 deletions(-) diff --git a/tests/phpunit/tests/oembed/controller.php b/tests/phpunit/tests/oembed/controller.php index c8d9f00af05e7..d7ee3720bb3b3 100644 --- a/tests/phpunit/tests/oembed/controller.php +++ b/tests/phpunit/tests/oembed/controller.php @@ -48,9 +48,11 @@ public function set_up() { parent::set_up(); /** @var WP_REST_Server $wp_rest_server */ - global $wp_rest_server; + global $wp_rest_server, $wp_scripts; $wp_rest_server = new Spy_REST_Server(); do_action( 'rest_api_init', $wp_rest_server ); + $wp_scripts = null; + wp_scripts(); add_filter( 'pre_http_request', array( $this, 'mock_embed_request' ), 10, 3 ); add_filter( 'oembed_result', array( $this, 'filter_oembed_result' ), 10, 3 ); diff --git a/tests/phpunit/tests/rest-api/rest-attachments-controller.php b/tests/phpunit/tests/rest-api/rest-attachments-controller.php index 4dd0b60172cb4..66f7e9fc6bf2a 100644 --- a/tests/phpunit/tests/rest-api/rest-attachments-controller.php +++ b/tests/phpunit/tests/rest-api/rest-attachments-controller.php @@ -120,6 +120,14 @@ public static function wpTearDownAfterClass() { public function set_up() { parent::set_up(); + // Avoid DNS lookups when validating URLs used by mocked image downloads. + add_filter( + 'pre_option_home', + static function () { + return 'https://example.com'; + } + ); + // Add an uploader role to test upload capabilities. add_role( 'uploader', 'File upload role' ); $role = get_role( 'uploader' ); diff --git a/tests/phpunit/tests/rest-api/rest-server.php b/tests/phpunit/tests/rest-api/rest-server.php index dce5a045f73db..71c908e3dffaf 100644 --- a/tests/phpunit/tests/rest-api/rest-server.php +++ b/tests/phpunit/tests/rest-api/rest-server.php @@ -54,6 +54,7 @@ public function set_up() { public function tear_down() { // Remove our temporary spy server. $GLOBALS['wp_rest_server'] = null; + unset( $GLOBALS['wp_rest_auth_cookie'] ); unset( $_REQUEST['_wpnonce'] ); parent::tear_down(); diff --git a/tests/phpunit/tests/rest-api/rest-sidebars-controller.php b/tests/phpunit/tests/rest-api/rest-sidebars-controller.php index dd01d4f2de4ee..8f5263c2567e6 100644 --- a/tests/phpunit/tests/rest-api/rest-sidebars-controller.php +++ b/tests/phpunit/tests/rest-api/rest-sidebars-controller.php @@ -45,6 +45,9 @@ public static function wpSetUpBeforeClass( $factory ) { public static function wpTearDownAfterClass() { self::delete_user( self::$admin_id ); self::delete_user( self::$author_id ); + + // Rebuild the default widgets after the class clears the shared factory. + wp_widgets_init(); } public function set_up() { @@ -53,20 +56,22 @@ public function set_up() { wp_set_current_user( self::$admin_id ); // Unregister all widgets and sidebars. - global $wp_registered_sidebars, $_wp_sidebars_widgets; + global $wp_registered_sidebars, $_wp_sidebars_widgets, $sidebars_widgets; $wp_registered_sidebars = array(); $_wp_sidebars_widgets = array(); + $sidebars_widgets = array(); update_option( 'sidebars_widgets', array() ); } public function clean_up_global_scope() { - global $wp_widget_factory, $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates; + global $wp_widget_factory, $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $sidebars_widgets; $wp_registered_sidebars = array(); $wp_registered_widgets = array(); $wp_registered_widget_controls = array(); $wp_registered_widget_updates = array(); $wp_widget_factory->widgets = array(); + $sidebars_widgets = array(); parent::clean_up_global_scope(); } @@ -85,12 +90,15 @@ private function setup_widgets( $option_name, $settings ) { } private function setup_sidebar( $id, $attrs = array(), $widgets = array() ) { - global $wp_registered_sidebars; + global $wp_registered_sidebars, $sidebars_widgets; + $sidebars_widgets = array(); + if ( empty( $widgets ) ) { + $sidebars_widgets['wp_inactive_widgets'] = array(); + } + $sidebars_widgets[ $id ] = $widgets; update_option( 'sidebars_widgets', - array( - $id => $widgets, - ) + $sidebars_widgets ); $wp_registered_sidebars[ $id ] = array_merge( array( @@ -111,6 +119,13 @@ private function setup_sidebar( $id, $attrs = array(), $widgets = array() ) { } } + private function register_new_sidebar( $args ) { + global $sidebars_widgets; + $sidebars_widgets = array( 'wp_inactive_widgets' => array() ); + + register_sidebar( $args ); + } + /** * @ticket 41683 */ @@ -398,7 +413,7 @@ public function test_get_items_active_sidebar_with_widgets() { * @ticket 53489 */ public function test_get_items_when_registering_new_sidebars() { - register_sidebar( + $this->register_new_sidebar( array( 'name' => 'New Sidebar', 'id' => 'new-sidebar', @@ -448,7 +463,7 @@ public function test_get_items_when_registering_new_sidebars() { * @ticket 53646 */ public function test_get_items_when_descriptions_have_markup() { - register_sidebar( + $this->register_new_sidebar( array( 'name' => 'New Sidebar', 'id' => 'new-sidebar', diff --git a/tests/phpunit/tests/rest-api/rest-themes-controller.php b/tests/phpunit/tests/rest-api/rest-themes-controller.php index aeaf92a8a27a1..8befefe6f5bf2 100644 --- a/tests/phpunit/tests/rest-api/rest-themes-controller.php +++ b/tests/phpunit/tests/rest-api/rest-themes-controller.php @@ -45,6 +45,20 @@ class WP_Test_REST_Themes_Controller extends WP_Test_REST_Controller_Testcase { */ protected static $current_theme; + /** + * Theme support state before the class tests run. + * + * @var array + */ + protected static $theme_features; + + /** + * Registered theme feature state before the class tests run. + * + * @var array + */ + protected static $registered_theme_features; + /** * The REST API route for themes. * @@ -113,7 +127,10 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { 'role' => 'contributor', ) ); - self::$current_theme = wp_get_theme(); + + self::$current_theme = wp_get_theme(); + self::$theme_features = $GLOBALS['_wp_theme_features']; + self::$registered_theme_features = $GLOBALS['_wp_registered_theme_features']; wp_set_current_user( self::$contributor_id ); } @@ -144,6 +161,13 @@ public function set_up() { switch_theme( 'rest-api' ); } + public function tear_down() { + $GLOBALS['_wp_theme_features'] = self::$theme_features; + $GLOBALS['_wp_registered_theme_features'] = self::$registered_theme_features; + + parent::tear_down(); + } + /** * Theme routes should be registered correctly. * diff --git a/tests/phpunit/tests/rest-api/rest-widget-types-controller.php b/tests/phpunit/tests/rest-api/rest-widget-types-controller.php index 3003c2e9741de..84365d453f0c5 100644 --- a/tests/phpunit/tests/rest-api/rest-widget-types-controller.php +++ b/tests/phpunit/tests/rest-api/rest-widget-types-controller.php @@ -57,6 +57,21 @@ public static function wpTearDownAfterClass() { self::delete_user( self::$subscriber_id ); } + public function set_up() { + parent::set_up(); + + global + $wp_widget_factory, + $wp_registered_widgets, + $wp_registered_widget_controls, + $wp_registered_widget_updates; + $wp_widget_factory->widgets = array(); + $wp_registered_widgets = array(); + $wp_registered_widget_controls = array(); + $wp_registered_widget_updates = array(); + wp_widgets_init(); + } + private function setup_widget( $id_base, $number, $settings ) { global $wp_widget_factory; @@ -108,7 +123,6 @@ public function test_context_param() { * @ticket 41683 */ public function test_get_items() { - wp_widgets_init(); wp_set_current_user( self::$admin_id ); $request = new WP_REST_Request( 'GET', '/wp/v2/widget-types' ); $response = rest_get_server()->dispatch( $request ); diff --git a/tests/phpunit/tests/rest-api/rest-widgets-controller.php b/tests/phpunit/tests/rest-api/rest-widgets-controller.php index c817cc07396aa..c0813c9f861b1 100644 --- a/tests/phpunit/tests/rest-api/rest-widgets-controller.php +++ b/tests/phpunit/tests/rest-api/rest-widgets-controller.php @@ -90,6 +90,11 @@ public static function wpSetUpBeforeClass( $factory ) { ); } + public static function wpTearDownAfterClass() { + // Rebuild the default widgets after the class clears the shared factory. + wp_widgets_init(); + } + public function set_up() { global $wp_widget_factory; diff --git a/tests/phpunit/tests/rest-api/wpRestUrlDetailsController.php b/tests/phpunit/tests/rest-api/wpRestUrlDetailsController.php index f39d9eb67e88f..4ed4276fe8f59 100644 --- a/tests/phpunit/tests/rest-api/wpRestUrlDetailsController.php +++ b/tests/phpunit/tests/rest-api/wpRestUrlDetailsController.php @@ -88,6 +88,14 @@ public static function wpTearDownAfterClass() { public function set_up() { parent::set_up(); + // Avoid a DNS lookup when validating the URL used by the mocked request. + add_filter( + 'pre_option_home', + static function () { + return self::URL_PLACEHOLDER; + } + ); + add_filter( 'pre_http_request', array( $this, 'mock_success_request_to_remote_url' ), 10, 3 ); // Disables usage of cache during major of tests. From e985910b4e603be38d937099d31a469cd6a1a193 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Thu, 20 Aug 2026 15:20:24 +0400 Subject: [PATCH 3/3] Tests: Avoid DNS in REST font face fixtures --- .../fonts/font-library/wpRestFontFacesController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/phpunit/tests/fonts/font-library/wpRestFontFacesController.php b/tests/phpunit/tests/fonts/font-library/wpRestFontFacesController.php index 8d66243668c46..f843adee36250 100644 --- a/tests/phpunit/tests/fonts/font-library/wpRestFontFacesController.php +++ b/tests/phpunit/tests/fonts/font-library/wpRestFontFacesController.php @@ -28,7 +28,7 @@ class Tests_REST_WpRestFontFacesController extends WP_Test_REST_Controller_Testc 'fontFamily' => '"Open Sans"', 'fontWeight' => '400', 'fontStyle' => 'normal', - 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf', + 'src' => 'https://example.org/wp-content/fonts/open-sans.ttf', ); public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { @@ -551,7 +551,7 @@ public function test_create_item_with_url_src() { 'fontFamily' => '"Open Sans"', 'fontWeight' => '200', 'fontStyle' => 'normal', - 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf', + 'src' => 'https://example.org/wp-content/fonts/open-sans.ttf', ) ) ); @@ -584,7 +584,7 @@ public function test_create_item_with_all_properties() { 'sizeAdjust' => '90%', 'unicodeRange' => 'U+0025-00FF, U+4??', 'preview' => 'https://s.w.org/images/fonts/wp-7.1/previews/open-sans/open-sans-400-normal.svg', - 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf', + 'src' => 'https://example.org/wp-content/fonts/open-sans.ttf', ); $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' ); @@ -651,7 +651,7 @@ public function test_create_item_default_theme_json_version() { array( 'fontFamily' => '"Open Sans"', 'fontWeight' => '200', - 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf', + 'src' => 'https://example.org/wp-content/fonts/open-sans.ttf', ) ) );