Commit 10bdbc1db80 for woocommerce
commit 10bdbc1db80e6e1e6cf833a757d46833d22423d2
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date: Mon Oct 19 19:21:34 2026 +0300
[tests] Reset the loaded shipping methods between tests (#69623)
* test: Reset the loaded shipping methods in WC_Unit_Test_Case
WC_Shipping keeps the methods it loaded on the singleton, and only
unregister_shipping_methods() drops them. A test that loads them under
its own filters or zones leaves that list for every later test: seven
classes, including Checkout, which leaves a lone pickup_location
method behind. #69117 reset it in ShippingControllerTest and the V4
shipping zone method tests after their leftovers broke other tests.
Drop the list in clear_wc_singleton_state(), with the other WC()
singleton state the rollback and hook restore miss. get_shipping_methods()
loads it again on next use.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Drop the per-class shipping method resets
WC_Unit_Test_Case now drops the loaded shipping methods after every
test, so the resets ShippingControllerTest and the V4 shipping zone
method tests ran in tearDown() are redundant. ShippingControllerTest
keeps unset( WC()->shipping ), which undoes a different leak: the
dynamic property one of its tests sets on the WC singleton.
The Totals and session pairs that the ShippingControllerTest reset
fixed in #69117 still pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(blocks): Run the Checkout block tests on WC_Unit_Test_Case
Blocks\Checkout extends WP_UnitTestCase, so the new shipping method
reset in WC_Unit_Test_Case doesn't reach it, and its local pickup test
still left a lone pickup_location method loaded on WC_Shipping. Move
it onto WC_Unit_Test_Case, as #69117 did for Totals and
RateLimitsTests, so its teardown drops the list too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Drop cleanup the rollback and base teardown already cover
Review simplification. Now that Blocks\Checkout runs on
WC_Unit_Test_Case, its remove_filter() after parent::tearDown() and
the wp_delete_post() at the end of a test duplicate the hook restore
and the database rollback. The V4 shipping zone method tests tracked
every zone they created only to delete it in tearDown(), which the
rollback also does; drop the tracking and the override.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Add testdox descriptions to shipping cleanup tests
Document the singleton cleanup and checkout pickup test outcomes using
the required testdox annotation. Address the missing annotations raised
in the PR review without changing test behavior.
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
diff --git a/.ai/skills/woocommerce-backend-dev/unit-tests.md b/.ai/skills/woocommerce-backend-dev/unit-tests.md
index f0940cc77ed..6ead6c9aedc 100644
--- a/.ai/skills/woocommerce-backend-dev/unit-tests.md
+++ b/.ai/skills/woocommerce-backend-dev/unit-tests.md
@@ -102,7 +102,7 @@ Choose cleanup from the test's base class; PHPUnit alone provides no database is
| Base class | Automatic isolation when parent setup/teardown runs |
| --- | --- |
| `WP_UnitTestCase` descendants, including `WP_HTTP_TestCase` and `WP_Test_REST_TestCase` | `$wpdb` transaction rollback, reset of the WordPress globals managed by the base, and hook snapshot restoration; the next setup flushes the object cache |
-| `WC_Unit_Test_Case` descendants, including `WC_REST_Unit_Test_Case` | All `WP_UnitTestCase` behavior plus WooCommerce cart/context, notices, and country-locale singleton cleanup, and, at each setup, unregistration of every `pa_*` taxonomy without an attribute row |
+| `WC_Unit_Test_Case` descendants, including `WC_REST_Unit_Test_Case` | All `WP_UnitTestCase` behavior plus WooCommerce cart/context, notices, country-locale and loaded shipping methods singleton cleanup, and, at each setup, unregistration of every `pa_*` taxonomy without an attribute row |
| `PHPUnit\Framework\TestCase` | No WordPress transaction, hook restoration, or global cleanup |
| Other custom base | Inspect its implementation; do not infer cleanup from PHPUnit or its name |
diff --git a/plugins/woocommerce/changelog/test-base-case-resets-loaded-shipping-methods b/plugins/woocommerce/changelog/test-base-case-resets-loaded-shipping-methods
new file mode 100644
index 00000000000..e20c47f4e45
--- /dev/null
+++ b/plugins/woocommerce/changelog/test-base-case-resets-loaded-shipping-methods
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Reset the loaded shipping methods in the base PHPUnit test case teardown; no production change.
diff --git a/plugins/woocommerce/tests/legacy/framework/class-wc-unit-test-case.php b/plugins/woocommerce/tests/legacy/framework/class-wc-unit-test-case.php
index 31d4a91e22e..e5bed3439b3 100644
--- a/plugins/woocommerce/tests/legacy/framework/class-wc-unit-test-case.php
+++ b/plugins/woocommerce/tests/legacy/framework/class-wc-unit-test-case.php
@@ -176,10 +176,10 @@ class WC_Unit_Test_Case extends WP_HTTP_TestCase {
/**
* Tear down test case.
*
- * The cart contents, the cart context, the queued notices, and the cached country
- * locale all live on the WC() singletons, which neither the per-test database
- * rollback nor the hook restore resets, so clear them here or they leak into every
- * later test in the process.
+ * The cart contents, the cart context, the queued notices, the cached country
+ * locale, and the loaded shipping methods all live on the WC() singletons, which
+ * neither the per-test database rollback nor the hook restore resets, so clear them
+ * here or they leak into every later test in the process.
*
* @since 11.1.0
*/
@@ -228,6 +228,9 @@ class WC_Unit_Test_Case extends WP_HTTP_TestCase {
// cache it produced.
WC()->countries->locale = array();
}
+
+ // WC_Shipping caches the loaded methods, including any a test's filters or zones added.
+ WC()->shipping()->unregister_shipping_methods();
}
/**
diff --git a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/ShippingZoneMethod/class-wc-rest-shipping-zone-method-v4-controller-tests.php b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/ShippingZoneMethod/class-wc-rest-shipping-zone-method-v4-controller-tests.php
index 6be6c5e344f..5fd31d9aad8 100644
--- a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/ShippingZoneMethod/class-wc-rest-shipping-zone-method-v4-controller-tests.php
+++ b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/ShippingZoneMethod/class-wc-rest-shipping-zone-method-v4-controller-tests.php
@@ -29,13 +29,6 @@ class WC_REST_Shipping_Zone_Method_V4_Controller_Tests extends WC_REST_Unit_Test
*/
private ShippingMethodSchema $schema;
- /**
- * Created shipping zones for cleanup.
- *
- * @var array
- */
- private array $created_zones = array();
-
/**
* Created user ID for testing purposes.
*
@@ -72,23 +65,6 @@ class WC_REST_Shipping_Zone_Method_V4_Controller_Tests extends WC_REST_Unit_Test
);
}
- /**
- * Cleanup after test.
- */
- public function tearDown(): void {
- // Clean up created zones.
- foreach ( $this->created_zones as $zone ) {
- $zone->delete();
- }
- $this->created_zones = array();
-
- // A test loads a custom method into the shared WC_Shipping list. The hook restore drops
- // its filter but not the loaded list, so reset the list to load again on next use.
- WC()->shipping()->unregister_shipping_methods();
-
- parent::tearDown();
- }
-
/**
* Cleanup after class.
*/
@@ -113,8 +89,6 @@ class WC_REST_Shipping_Zone_Method_V4_Controller_Tests extends WC_REST_Unit_Test
$zone->set_locations( $locations );
$zone->save();
- $this->created_zones[] = $zone;
-
return $zone;
}
diff --git a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/Checkout.php b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/Checkout.php
index 1a48218a05b..cf6754d0f5c 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/Checkout.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/Checkout.php
@@ -14,7 +14,7 @@ use Automattic\WooCommerce\Tests\Blocks\Mocks\CheckoutMock;
*
* @since $VID:$
*/
-class Checkout extends \WP_UnitTestCase {
+class Checkout extends \WC_Unit_Test_Case {
/**
* @var AssetDataRegistryMock The asset data registry mock.
*/
@@ -43,7 +43,7 @@ class Checkout extends \WP_UnitTestCase {
* @return void
* @throws \Exception If the API class is not registered with container.
*/
- protected function setUp(): void {
+ public function setUp(): void {
parent::setUp();
$this->asset_api = Package::container()->get( API::class );
@@ -61,9 +61,8 @@ class Checkout extends \WP_UnitTestCase {
*
* @return void
*/
- protected function tearDown(): void {
+ public function tearDown(): void {
parent::tearDown();
- remove_filter( 'woocommerce_logging_class', array( $this, 'override_wc_logger' ) );
// A test registers a CheckoutMock block type, and the block type registry outlives a test.
if ( \WP_Block_Type_Registry::get_instance()->is_registered( 'woocommerce/checkout-mock' ) ) {
@@ -72,7 +71,7 @@ class Checkout extends \WP_UnitTestCase {
}
/**
- * Checks the local pickup title is updated when the Checkout block is saved.
+ * @testdox The local pickup title is updated when the Checkout block is saved.
* @return void
*/
public function test_local_pickup_title_change() {
@@ -137,7 +136,6 @@ class Checkout extends \WP_UnitTestCase {
$data_from_registry = $this->registry->get();
$this->assertEquals( 'Changed pickup', $data_from_registry['localPickupText'] );
- wp_delete_post( $page_id );
}
/**
diff --git a/plugins/woocommerce/tests/php/src/Blocks/Shipping/ShippingControllerTest.php b/plugins/woocommerce/tests/php/src/Blocks/Shipping/ShippingControllerTest.php
index c93708745f4..d882fd06d79 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/Shipping/ShippingControllerTest.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/Shipping/ShippingControllerTest.php
@@ -97,10 +97,8 @@ class ShippingControllerTest extends \WC_Unit_Test_Case {
foreach ( $this->previous_shipping_address as $key => $value ) {
WC()->customer->{"set_shipping_{$key}"}( $value );
}
- // A test may null WC()->shipping, which leaves a dynamic property on the WC singleton,
- // and register a lone pickup method on the shared WC_Shipping. Undo both.
+ // A test may null WC()->shipping, which leaves a dynamic property on the WC singleton.
unset( WC()->shipping );
- WC()->shipping()->unregister_shipping_methods();
} finally {
parent::tearDown();
}
diff --git a/plugins/woocommerce/tests/php/src/UnitTestCaseTearDownTest.php b/plugins/woocommerce/tests/php/src/UnitTestCaseTearDownTest.php
index 48bce12ed80..be60c83ead7 100644
--- a/plugins/woocommerce/tests/php/src/UnitTestCaseTearDownTest.php
+++ b/plugins/woocommerce/tests/php/src/UnitTestCaseTearDownTest.php
@@ -54,7 +54,7 @@ class UnitTestCaseTearDownTest extends \WC_Unit_Test_Case {
}
/**
- * Every piece of singleton state the teardown is responsible for is cleared.
+ * @testdox Every piece of singleton state the teardown is responsible for is cleared.
*/
public function test_clear_wc_singleton_state_clears_what_survives_the_parent_teardown(): void {
$locale_filter = function ( $locale ) {
@@ -86,6 +86,9 @@ class UnitTestCaseTearDownTest extends \WC_Unit_Test_Case {
};
add_action( 'woocommerce_before_cart_emptied', $cart_emptied_callback );
+ WC()->shipping()->load_shipping_methods();
+ $this->assertIsArray( WC()->shipping()->shipping_methods, 'The shipping methods should be loaded.' );
+
// What tearDown() runs before handing off to the parent.
$this->clear_wc_singleton_state();
remove_action( 'woocommerce_before_cart_emptied', $cart_emptied_callback );
@@ -97,6 +100,7 @@ class UnitTestCaseTearDownTest extends \WC_Unit_Test_Case {
$this->assertTrue( WC()->cart->is_empty(), 'The cart should have been emptied.' );
$this->assertSame( 'shortcode', WC()->cart->cart_context, 'The cart context should be back to shortcode.' );
$this->assertSame( 0, wc_notice_count(), 'The notice queue should have been cleared.' );
+ $this->assertNull( WC()->shipping()->shipping_methods, 'The loaded shipping methods should have been dropped.' );
$this->assertFalse( $clear_persistent_cart, 'Teardown should leave persistent cart cleanup to the database rollback.' );
$this->assertNotSame(
self::LEAKED_LOCALE_LABEL,