Commit 81badfa4a28 for woocommerce
commit 81badfa4a283f6238d50c49228fb249aaafe422f
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date: Sun Nov 15 21:30:50 2026 +0200
[tests] Fix the test leaks that fail 47 tests in random order (#70981)
* test: Reset the Analytics reload flag between tests
Changing the woocommerce_analytics_enabled option sets the static
Analytics::$is_updated flag, so that the next settings save reloads the
page: maybe_reload_page() redirects and calls exit(). In production that
is one admin request. In tests the flag outlives the test that set it,
and the test bootstrap sets $_SERVER['REQUEST_URI'], so the next test
that calls WC_Admin_Settings::save() ends the whole PHPUnit process.
The exit status is 0 and every test after it silently does not run.
Ten tests change the option. In the default order the settings tests
run before them, so the full suite finishes; in reverse order, or a
random order, the run stops early. Three settings redirect tests that
do run before the stop also fail there, because the save redirects to
the request URI instead of where they expect.
Reset the flag in WC_Unit_Test_Case::tearDown(), as the base class
already does for other static state.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Fail the run when a test ends the PHPUnit process early
A test that reaches exit() or die() ends the PHP process. PHPUnit
prints no summary and the process exits with status 0, so the tests
after it never run and CI still reports success.
Add a listener, registered next to the external HTTP guard, that counts
open suites and tracks the test in progress. A shutdown function reports
a run that has not finished, naming the test that was running, and
exits with status 1. A fatal error also lands here: it already prints
its own message, and the status becomes 1 instead of 255.
error_get_last() cannot tell the two apart, because WordPress's fatal
error handler runs first and can raise a warning that replaces it.
PHPUnit does not load listeners in separate-process children, so those
tests are covered by the parent process only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Restore the object cache mode after each test
Tests switch wp_using_ext_object_cache() on to exercise transients in
the object cache, then put the old value back. That value starts as
null, and wp_using_ext_object_cache( null ) does nothing, so the switch
outlives the test. Every later test then stores transients in the
object cache, and seven tests that need database-backed transients fail
in random order (RemoteFreeExtensions InitTest, WC_Helper_Updater_Test,
MobileAppQRLoginTest, the variable product price transient pruning).
Save the global in WC_Unit_Test_Case::setUp() and write it back in
tearDown(), next to the $_SERVER and constants restores.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Keep the approved download directory cache out of later tests
ApprovedDirectories\Register memoizes which download URLs are valid, for
the life of the process. test_fetching_of_approved_downloads disables a
rule and reads the downloads, so the memo records that URL as invalid.
The rollback re-enables the rule but not the memo, and the next set_up()
re-adds the rule through add_approved_directory(), which returns early
for an existing row without clearing the memo. All 32 later tests in
the class then fail creating their fixture product.
Delete the rules before adding them, which clears the memo through the
class API, and call parent::set_up() first: the fixture writes ran
before the transaction started, so every test committed a product, two
users and option changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Stop WC_Tax_Test committing its cleanup
tearDown() ran its cleanup after parent::tearDown(), outside the
transaction, so it committed: it deleted woocommerce_shipping_tax_class,
woocommerce_tax_classes and woocommerce_calc_taxes, every tax rate, the
tax classes and the products. Later tests then calculated orders
without shipping tax, and three WC_Tests_CRUD_Orders tests failed.
The rollback already undoes everything the cleanup did, so drop it with
the properties that only fed it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Put back the main query after the breadcrumb tests
WC_Breadcrumb_Test tearDown() set $wp_query and $post to null, so the
next test that called get_query_var() had no main query and fataled
(ProductCollection QueryBuilder). wp_reset_query() points $wp_query back
at the main query and resets $post.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Make the email preview date placeholder test set its subject
Only the customer note subject without email improvements contains
{order_date}, and the shared mailer keeps the subject it was built
with. The class turns email improvements on, so the test only passed
when something else built the mailer first with them off. Set the
preview subject transient the preview reads instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Start the push notification tests without the post type
WordPress resets post types between tests only in its own suite, so a
push token post type registered by an earlier test, such as
PushTokenRestControllerTest, was still there when
test_on_init_does_not_register_post_types_when_disabled_via_filter ran.
Unregister it in setUp() as well as tearDown().
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Keep checkout cookies out of later tests
The Store API checkout tests copy every wc_setcookie() call into
$_COOKIE, and creating an account during checkout logs the customer in,
which leaves session and login cookies there. WordPress resets $_GET
and $_POST between tests but not $_COOKIE, so a later AJAX test that
needs a guest without a session failed.
Restore $_COOKIE in the checkout tests tearDown(), and have the AJAX
test start from no cookies.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Reset the payment suggestion memo before counting it
EvaluateSuggestion keeps a static memo that other tests fill, and
test_memo_set_correctly counted its entries. Reset it first.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Explain why the breadcrumb tests keep wp_reset_query()
The CI Lint job failed on WordPress.WP.DiscouragedFunctions, which
flags wp_reset_query() and suggests wp_reset_postdata() instead.
That swap would bring the leak back. The breadcrumb tests replace
$wp_query with their own WP_Query, and wp_reset_postdata() only resets
$post from whatever $wp_query holds. wp_reset_query() is what points
$wp_query back at the main query, so later tests that call
get_query_var() still have one.
Keep the call, suppress the sniff on that line, and say why.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Delete the size attribute the UCP cart fixtures create
UcpCart creates a global "size" attribute (label "size") in
wpSetUpBeforeClass(), outside any test transaction, and its
wpTearDownAfterClass() deleted the products but not the attribute. A
later Store API cart test that asks the fixture helper for a "Size"
attribute then reused that row, label included, and failed comparing
"Size" with "size" when the files run in reverse order.
Delete the attribute after the class, unless it existed before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: Keep a reused size attribute when the UCP cart fixtures clean up
The UcpCart class fixture deletes the "size" attribute at class
teardown when it created it, and decided that by looking up the slug
"size" before calling FixtureData::get_product_attribute(). The helper
matches "size" against attribute labels before it falls back to the
slug, so an existing attribute labelled "size" with another slug was
reused by the helper, judged new by the slug check, and deleted.
Record the attribute IDs before the call and treat the returned ID as
created only when it was not among them.
Refs #70981
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/test-random-order-leaks b/plugins/woocommerce/changelog/test-random-order-leaks
new file mode 100644
index 00000000000..5031a9be325
--- /dev/null
+++ b/plugins/woocommerce/changelog/test-random-order-leaks
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Fix PHPUnit tests that leak state into later tests and fail in random order; 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 dc174f8809f..5b1273cec79 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
@@ -78,6 +78,14 @@ class WC_Unit_Test_Case extends WP_HTTP_TestCase {
*/
private $constant_overrides_at_setup = null;
+ /**
+ * Whether WordPress used an external object cache at setUp(), wrapped so that WordPress's own
+ * null (never set) can be saved too, or null until setUp() saves it.
+ *
+ * @var array{using: bool|null}|null
+ */
+ private $object_cache_mode_at_setup = null;
+
/**
* The registered block types at setUp(), by name, or null until setUp() saves them.
*
@@ -196,6 +204,7 @@ class WC_Unit_Test_Case extends WP_HTTP_TestCase {
$this->server_at_setup = $_SERVER;
$this->constant_overrides_at_setup = Constants::$set_constants;
+ $this->object_cache_mode_at_setup = array( 'using' => $GLOBALS['_wp_using_ext_object_cache'] ?? null );
$this->block_types_at_setup = WP_Block_Type_Registry::get_instance()->get_all_registered();
}
@@ -240,6 +249,7 @@ class WC_Unit_Test_Case extends WP_HTTP_TestCase {
// Each restore then finds no saved state and leaves the current one alone.
$this->restore_server_superglobal();
$this->restore_constant_overrides();
+ $this->restore_object_cache_mode();
$this->restore_block_type_registry();
$this->restore_mailer();
@@ -413,6 +423,19 @@ class WC_Unit_Test_Case extends WP_HTTP_TestCase {
Constants::$set_constants = $this->constant_overrides_at_setup;
}
+ /**
+ * Put back whether WordPress uses an external object cache, as it was at setUp(). Tests switch it with
+ * wp_using_ext_object_cache() to exercise transients in the object cache, and putting the old value
+ * back through that function does nothing when it was null, so the switch would outlive the test.
+ */
+ protected function restore_object_cache_mode(): void {
+ if ( null === $this->object_cache_mode_at_setup ) {
+ return;
+ }
+
+ $GLOBALS['_wp_using_ext_object_cache'] = $this->object_cache_mode_at_setup['using']; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Restores the value saved at setUp().
+ }
+
/**
* Put back the block types from setUp(): unregister the ones a test added or replaced, and
* register again the ones it removed. The registry is a singleton that outlives the test.
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/payment-gateway-suggestions/evaluate-suggestion.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/payment-gateway-suggestions/evaluate-suggestion.php
index de247d24969..14d5768cbeb 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/payment-gateway-suggestions/evaluate-suggestion.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/features/payment-gateway-suggestions/evaluate-suggestion.php
@@ -326,6 +326,9 @@ class WC_Admin_Tests_PaymentGatewaySuggestions_EvaluateSuggestion extends WC_Uni
* Test that the memo is set correctly.
*/
public function test_memo_set_correctly() {
+ // Other tests evaluate specs through the same static memo.
+ TestableEvaluateSuggestion::reset_memo();
+
$specs = array(
array(
'id' => 'test-gateway-1',
diff --git a/plugins/woocommerce/tests/php/includes/abstracts/class-wc-abstract-product-test.php b/plugins/woocommerce/tests/php/includes/abstracts/class-wc-abstract-product-test.php
index d4835b54f20..f8e0be26056 100644
--- a/plugins/woocommerce/tests/php/includes/abstracts/class-wc-abstract-product-test.php
+++ b/plugins/woocommerce/tests/php/includes/abstracts/class-wc-abstract-product-test.php
@@ -44,12 +44,18 @@ class WC_Abstract_Product_Test extends WC_Unit_Test_Case {
* Setup items we need repeatedly across tests in this class.
*/
public function set_up() {
+ parent::set_up();
+
self::enable_direct_product_attribute_lookup_updates();
$this->admin_user = self::factory()->user->create( array( 'role' => 'administrator' ) );
$this->shop_manager_user = self::factory()->user->create( array( 'role' => 'shop_manager' ) );
$this->download_directories = wc_get_container()->get( Download_Directories::class );
+ // Start from exactly these two enabled rules. Deleting and adding rules also clears the
+ // valid-path cache Register keeps for the whole process, which the rollback leaves behind:
+ // a test that disables a rule would otherwise make later tests reject this product's files.
$this->download_directories->set_mode( Download_Directories::MODE_ENABLED );
+ $this->download_directories->delete_all();
$this->download_directories->add_approved_directory( 'https://always.trusted/' );
$this->download_directories->add_approved_directory( 'https://new.supplier/' );
@@ -65,8 +71,6 @@ class WC_Abstract_Product_Test extends WC_Unit_Test_Case {
),
)
);
-
- parent::set_up();
}
/**
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php b/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php
index d0470217ecf..f7dbc8d971d 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-ajax-test.php
@@ -3794,10 +3794,12 @@ class WC_AJAX_Test extends \WP_Ajax_UnitTestCase {
*/
public function test_update_order_review_skips_reload_without_session(): void {
$original_post = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Preserve test globals before building the request.
+ $original_cookies = $_COOKIE;
$original_session = WC()->session;
try {
wp_set_current_user( 0 );
+ $_COOKIE = array();
WC()->session = new WC_Session_Handler();
WC()->session->init_session_cookie();
@@ -3816,6 +3818,7 @@ class WC_AJAX_Test extends \WP_Ajax_UnitTestCase {
} finally {
WC()->session = $original_session;
$_POST = $original_post;
+ $_COOKIE = $original_cookies;
}
}
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-breadcrumb-test.php b/plugins/woocommerce/tests/php/includes/class-wc-breadcrumb-test.php
index 1dd68d5d58d..5d06c12c45f 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-breadcrumb-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-breadcrumb-test.php
@@ -33,9 +33,9 @@ class WC_Breadcrumb_Test extends \WC_Unit_Test_Case {
public function tearDown(): void {
parent::tearDown();
$this->sut->reset();
- global $wp_query, $post;
- $wp_query = null; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
- $post = null; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ // Put back the main query the tests replace, rather than leaving later tests without one.
+ // wp_reset_postdata() would only reset $post from the replaced query, not restore $wp_query.
+ wp_reset_query(); // phpcs:ignore WordPress.WP.DiscouragedFunctions.wp_reset_query_wp_reset_query
}
/**
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-tax-test.php b/plugins/woocommerce/tests/php/includes/class-wc-tax-test.php
index b1d71e2088d..6a451b0f40b 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-tax-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-tax-test.php
@@ -13,34 +13,6 @@ declare( strict_types=1 );
*/
class WC_Tax_Test extends WC_Unit_Test_Case {
- /**
- * Track whether we created the reduced-rate tax class.
- *
- * @var bool
- */
- private $created_reduced_rate_class = false;
-
- /**
- * Track whether we created the zero-rate tax class.
- *
- * @var bool
- */
- private $created_zero_rate_class = false;
-
- /**
- * Track created products for cleanup.
- *
- * @var array
- */
- private $created_products = array();
-
- /**
- * Store the original value of woocommerce_calc_taxes.
- *
- * @var string|null
- */
- private $original_calc_taxes = null;
-
/**
* Set up test.
*/
@@ -50,8 +22,6 @@ class WC_Tax_Test extends WC_Unit_Test_Case {
// Clear any existing tax rates and settings.
$this->clean_up_tax_rates();
- // Store and set woocommerce_calc_taxes option.
- $this->original_calc_taxes = get_option( 'woocommerce_calc_taxes', null );
update_option( 'woocommerce_calc_taxes', 'yes' );
// Ensure required tax classes exist for testing.
@@ -61,41 +31,6 @@ class WC_Tax_Test extends WC_Unit_Test_Case {
WC()->cart->empty_cart();
}
- /**
- * Clean up after test.
- */
- public function tearDown(): void {
- parent::tearDown();
-
- // Clean up created products.
- foreach ( $this->created_products as $product_id ) {
- wp_delete_post( $product_id, true );
- }
- $this->created_products = array();
-
- // Clean up tax rates.
- $this->clean_up_tax_rates();
-
- // Reset tax settings.
- delete_option( 'woocommerce_shipping_tax_class' );
- delete_option( 'woocommerce_tax_classes' );
-
- // Restore woocommerce_calc_taxes option to its original value.
- if ( null !== $this->original_calc_taxes ) {
- update_option( 'woocommerce_calc_taxes', $this->original_calc_taxes );
- } else {
- delete_option( 'woocommerce_calc_taxes' );
- }
-
- // Only clean up tax classes we created during testing.
- if ( $this->created_reduced_rate_class ) {
- WC_Tax::delete_tax_class_by( 'slug', 'reduced-rate' );
- }
- if ( $this->created_zero_rate_class ) {
- WC_Tax::delete_tax_class_by( 'slug', 'zero-rate' );
- }
- }
-
/**
* Helper method to clean up all tax rates.
*/
@@ -116,18 +51,12 @@ class WC_Tax_Test extends WC_Unit_Test_Case {
// Check and create reduced-rate tax class if needed.
if ( ! in_array( 'reduced-rate', $existing_tax_class_slugs, true ) ) {
- $reduced_class = WC_Tax::create_tax_class( 'Reduced rate', 'reduced-rate' );
- if ( is_array( $reduced_class ) ) {
- $this->created_reduced_rate_class = true;
- }
+ WC_Tax::create_tax_class( 'Reduced rate', 'reduced-rate' );
}
// Check and create zero-rate tax class if needed.
if ( ! in_array( 'zero-rate', $existing_tax_class_slugs, true ) ) {
- $zero_class = WC_Tax::create_tax_class( 'Zero rate', 'zero-rate' );
- if ( is_array( $zero_class ) ) {
- $this->created_zero_rate_class = true;
- }
+ WC_Tax::create_tax_class( 'Zero rate', 'zero-rate' );
}
}
@@ -145,8 +74,6 @@ class WC_Tax_Test extends WC_Unit_Test_Case {
$product->set_tax_class( $tax_class );
$product->save();
- $this->created_products[] = $product->get_id();
-
return $product;
}
@@ -321,8 +248,6 @@ class WC_Tax_Test extends WC_Unit_Test_Case {
$product->set_tax_status( 'none' );
$product->save();
- $this->created_products[] = $product->get_id();
-
WC()->cart->add_to_cart( $product->get_id(), 1 );
$shipping_rates = WC_Tax::get_shipping_tax_rates();
@@ -425,8 +350,6 @@ class WC_Tax_Test extends WC_Unit_Test_Case {
$product->set_tax_status( 'none' );
$product->save();
- $this->created_products[] = $product->get_id();
-
WC()->cart->add_to_cart( $product->get_id(), 1 );
// Use reflection to test private method.
diff --git a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Checkout.php b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Checkout.php
index d135bf3d032..37373e1eba9 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Checkout.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/Checkout.php
@@ -63,6 +63,14 @@ class Checkout extends \WP_Test_REST_TestCase {
*/
private $paypal_gateway_before_test;
+ /**
+ * $_COOKIE before the test. filter_woocommerce_set_cookie_enabled() writes the cookies the
+ * checkout sets, such as the session and login cookies, into it.
+ *
+ * @var array<string, string>
+ */
+ private $cookies_before_test = array();
+
/**
* Tax rate IDs inserted by the current test, removed in tearDown().
*
@@ -126,6 +134,7 @@ class Checkout extends \WP_Test_REST_TestCase {
protected function setUp(): void {
parent::setUp();
+ $this->cookies_before_test = $_COOKIE;
add_filter( 'woocommerce_set_cookie_enabled', array( $this, 'filter_woocommerce_set_cookie_enabled' ), 10, 4 );
update_option( 'woocommerce_checkout_phone_field', 'optional' );
@@ -213,6 +222,7 @@ class Checkout extends \WP_Test_REST_TestCase {
$this->invalidate_checkout_option_caches();
WC()->payment_gateways()->payment_gateways = $this->payment_gateways_before_test;
\WC_Gateway_Paypal::set_instance( $this->paypal_gateway_before_test );
+ $_COOKIE = $this->cookies_before_test;
}
}
}
diff --git a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/UcpCart.php b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/UcpCart.php
index f1acb7d29a6..6a420baf6ca 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/UcpCart.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/StoreApi/Routes/UcpCart.php
@@ -39,6 +39,13 @@ class UcpCart extends UcpCartTestCase {
'variation' => 0,
);
+ /**
+ * The global size attribute the class fixtures created, or 0 when one already existed.
+ *
+ * @var int
+ */
+ private static $size_attribute_id = 0;
+
/**
* Create immutable fixtures before route registration starts.
*/
@@ -81,9 +88,14 @@ class UcpCart extends UcpCartTestCase {
self::$limited_stock_id = $limited[0]->get_id();
- $fixtures = new \Automattic\WooCommerce\Tests\Blocks\Helpers\FixtureData();
- $parent = $fixtures->get_variable_product( array( 'name' => 'UCP Cart Tee' ), array( $fixtures->get_product_attribute( 'size', array( 'small', 'large' ) ) ) );
- $variation = $fixtures->get_variation_product(
+ $fixtures = new \Automattic\WooCommerce\Tests\Blocks\Helpers\FixtureData();
+ $attribute_ids_before = array_map( 'intval', wc_get_attribute_taxonomy_ids() );
+ $size = $fixtures->get_product_attribute( 'size', array( 'small', 'large' ) );
+ // The helper matches "size" as a label before a slug, so check the ID it returns, not the slug.
+ $size_existed = in_array( (int) $size['attribute_id'], $attribute_ids_before, true );
+ self::$size_attribute_id = $size_existed ? 0 : $size['attribute_id'];
+ $parent = $fixtures->get_variable_product( array( 'name' => 'UCP Cart Tee' ), array( $size ) );
+ $variation = $fixtures->get_variation_product(
$parent->get_id(),
array( 'pa_size' => 'small' ),
array( 'regular_price' => '12.00' )
@@ -110,6 +122,13 @@ class UcpCart extends UcpCartTestCase {
array( self::$limited_stock_id, self::$variable['variation'], self::$variable['parent'] )
)
);
+
+ // Class fixtures are committed, so a created attribute would outlive the class, and a later
+ // fixture asking for a "Size" attribute would get this one with its lowercase label.
+ if ( self::$size_attribute_id ) {
+ wc_delete_attribute( self::$size_attribute_id );
+ self::$size_attribute_id = 0;
+ }
}
/**
diff --git a/plugins/woocommerce/tests/php/src/Internal/Admin/EmailPreview/EmailPreviewTest.php b/plugins/woocommerce/tests/php/src/Internal/Admin/EmailPreview/EmailPreviewTest.php
index d09018deb36..06dff1217b2 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Admin/EmailPreview/EmailPreviewTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Admin/EmailPreview/EmailPreviewTest.php
@@ -135,6 +135,9 @@ class EmailPreviewTest extends WC_Unit_Test_Case {
// {order_number} placeholder
$this->assertStringContainsString( '12345', $subject );
+ // Only the customer note's subject without email improvements has {order_date}, and the shared
+ // mailer keeps whichever subject it was built with, so set the one the preview reads.
+ set_transient( 'woocommerce_customer_note_subject', 'Note added to your {site_title} order from {order_date}' );
$this->sut->set_email_type( 'WC_Email_Customer_Note' );
$subject = $this->sut->get_subject();
// {order_date} placeholder
diff --git a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/PushNotificationsTest.php b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/PushNotificationsTest.php
index fe0b3a9f615..d1f6d57d43a 100644
--- a/plugins/woocommerce/tests/php/src/Internal/PushNotifications/PushNotificationsTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/PushNotifications/PushNotificationsTest.php
@@ -32,6 +32,18 @@ use WP_REST_Response;
class PushNotificationsTest extends WC_Unit_Test_Case {
use PushNotificationsTestTrait;
+ /**
+ * Start without the push token post type. WordPress does not reset post types between plugin
+ * tests, so one registered by an earlier test would still be there.
+ */
+ public function setUp(): void {
+ parent::setUp();
+
+ if ( post_type_exists( PushToken::POST_TYPE ) ) {
+ unregister_post_type( PushToken::POST_TYPE );
+ }
+ }
+
/**
* Tear down the test case.
*/
diff --git a/plugins/woocommerce/tests/php/src/UnitTestCaseTearDownTest.php b/plugins/woocommerce/tests/php/src/UnitTestCaseTearDownTest.php
index 89020bdbfe1..f1b8ab1e2f6 100644
--- a/plugins/woocommerce/tests/php/src/UnitTestCaseTearDownTest.php
+++ b/plugins/woocommerce/tests/php/src/UnitTestCaseTearDownTest.php
@@ -267,6 +267,18 @@ class UnitTestCaseTearDownTest extends \WC_Unit_Test_Case {
)();
}
+ /**
+ * @testdox Whether WordPress uses an external object cache is put back as it was at setUp(), even when that was unset.
+ */
+ public function test_restore_object_cache_mode_undoes_a_switch(): void {
+ $mode_at_setup = $GLOBALS['_wp_using_ext_object_cache'] ?? null;
+ wp_using_ext_object_cache( true !== $mode_at_setup );
+
+ $this->restore_object_cache_mode();
+
+ $this->assertSame( $mode_at_setup, $GLOBALS['_wp_using_ext_object_cache'] ?? null, 'The object cache mode should be back to what it was at setUp().' );
+ }
+
/**
* @testdox The restores leave state alone for a test whose setUp() never reached the base class.
*/
@@ -274,21 +286,25 @@ class UnitTestCaseTearDownTest extends \WC_Unit_Test_Case {
// Like a test that skips in setUp() before calling parent::setUp(): PHPUnit still runs its tearDown().
$case = new class( 'placeholder' ) extends \WC_Unit_Test_Case {
/**
- * Run the three restores on a case that saved no state.
+ * Run the restores on a case that saved no state.
*/
public function restore_without_setup(): void {
$this->restore_server_superglobal();
$this->restore_constant_overrides();
$this->restore_block_type_registry();
+ $this->restore_object_cache_mode();
}
};
Constants::set_constant( 'WC_TEARDOWN_TEST_KEPT', 'kept' );
$server = $_SERVER;
$overrides = Constants::$set_constants;
$block_types = \WP_Block_Type_Registry::get_instance()->get_all_registered();
+ wp_using_ext_object_cache( true );
$case->restore_without_setup();
+ $this->assertTrue( wp_using_ext_object_cache(), 'The object cache mode should be left as it was.' );
+
$this->assertSame( $server, $_SERVER, '$_SERVER should be left as it was.' );
$this->assertSame( $overrides, Constants::$set_constants, 'Constants overrides should be left as they were.' );
$this->assertSame( $block_types, \WP_Block_Type_Registry::get_instance()->get_all_registered(), 'The block type registry should be left as it was.' );