Commit 52b6e139a7c for woocommerce
commit 52b6e139a7c87fa7c6e1e56b390255c814aef93f
Author: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com>
Date: Wed Jul 8 19:17:45 2026 +0300
test: remove real sleep() from PHP unit tests (#66413)
diff --git a/plugins/woocommerce/changelog/testops-212-remove-real-sleep-from-php-unit-tests b/plugins/woocommerce/changelog/testops-212-remove-real-sleep-from-php-unit-tests
new file mode 100644
index 00000000000..09e16a518c5
--- /dev/null
+++ b/plugins/woocommerce/changelog/testops-212-remove-real-sleep-from-php-unit-tests
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Remove real sleep() calls from PHP unit tests by controlling timestamps explicitly; no production change.
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-tracker-test.php b/plugins/woocommerce/tests/php/includes/class-wc-tracker-test.php
index cae702a1673..7d1775325b9 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-tracker-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-tracker-test.php
@@ -344,29 +344,32 @@ class WC_Tracker_Test extends \WC_Unit_Test_Case {
$this->assertEquals( $tracking_data['woocommerce_allow_tracking_last_modified'], 'unknown' );
$this->assertEquals( $tracking_data['woocommerce_allow_tracking_first_optin'], 'unknown' );
- $time_one = time();
+ $before = time();
update_option( 'woocommerce_allow_tracking', 'yes' );
$tracking_data = WC_Tracker::get_tracking_data();
$this->assertEquals( $tracking_data['woocommerce_allow_tracking'], 'yes' );
- $this->assertTrue( $tracking_data['woocommerce_allow_tracking_last_modified'] >= $time_one );
- $this->assertTrue( $tracking_data['woocommerce_allow_tracking_first_optin'] >= $time_one );
+ $this->assertGreaterThanOrEqual( $before, (int) $tracking_data['woocommerce_allow_tracking_last_modified'] );
+ $this->assertGreaterThanOrEqual( $before, (int) $tracking_data['woocommerce_allow_tracking_first_optin'] );
- sleep( 1 ); // be sure $time_two is at least one second after $time_one.
- $time_two = time();
+ // first_optin is recorded once on the first opt-in and must never change afterwards.
+ $first_optin = (int) get_option( 'woocommerce_allow_tracking_first_optin' );
+
+ // last_modified must be refreshed to the current time on every tracking change. Capturing the
+ // time immediately before each update keeps this deterministic without waiting on the clock.
+ $before = time();
update_option( 'woocommerce_allow_tracking', 'no' );
$tracking_data = WC_Tracker::get_tracking_data();
$this->assertEquals( $tracking_data['woocommerce_allow_tracking'], 'no' );
- $this->assertTrue( $tracking_data['woocommerce_allow_tracking_last_modified'] >= $time_two );
- $this->assertTrue( $tracking_data['woocommerce_allow_tracking_first_optin'] >= $time_one && $tracking_data['woocommerce_allow_tracking_first_optin'] < $time_two );
+ $this->assertGreaterThanOrEqual( $before, (int) $tracking_data['woocommerce_allow_tracking_last_modified'] );
+ $this->assertEquals( $first_optin, (int) $tracking_data['woocommerce_allow_tracking_first_optin'] );
- sleep( 1 ); // be sure $time_three is at least one second after $time_two.
- $time_three = time();
+ $before = time();
update_option( 'woocommerce_allow_tracking', 'yes' );
$tracking_data = WC_Tracker::get_tracking_data();
$this->assertEquals( $tracking_data['woocommerce_allow_tracking'], 'yes' );
- $this->assertTrue( $tracking_data['woocommerce_allow_tracking_last_modified'] >= $time_three );
- $this->assertTrue( $tracking_data['woocommerce_allow_tracking_first_optin'] >= $time_one && $tracking_data['woocommerce_allow_tracking_first_optin'] < $time_two );
+ $this->assertGreaterThanOrEqual( $before, (int) $tracking_data['woocommerce_allow_tracking_last_modified'] );
+ $this->assertEquals( $first_optin, (int) $tracking_data['woocommerce_allow_tracking_first_optin'] );
// Restore everything as it was.
update_option( 'woocommerce_allow_tracking', $current_woocommerce_allow_tracking );
diff --git a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/Customers/class-wc-rest-customers-v4-controller-tests.php b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/Customers/class-wc-rest-customers-v4-controller-tests.php
index 94f3be57999..725702fe080 100644
--- a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/Customers/class-wc-rest-customers-v4-controller-tests.php
+++ b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/Customers/class-wc-rest-customers-v4-controller-tests.php
@@ -165,6 +165,22 @@ class WC_REST_Customers_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
return $customer;
}
+ /**
+ * Backdate a customer's registration timestamp so ordering-by-registration-date tests are
+ * deterministic without waiting on the real clock.
+ *
+ * @param int $user_id User ID.
+ * @param int $seconds_ago How many seconds before "now" the user should appear to have registered.
+ */
+ private function set_user_registered( int $user_id, int $seconds_ago ): void {
+ wp_update_user(
+ array(
+ 'ID' => $user_id,
+ 'user_registered' => gmdate( 'Y-m-d H:i:s', time() - $seconds_ago ),
+ )
+ );
+ }
+
/**
* Helper method to validate response against schema.
*
@@ -1044,9 +1060,6 @@ class WC_REST_Customers_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
)
);
- // Wait a moment to ensure different registration times.
- sleep( 1 );
-
$customer2 = $this->create_test_customer(
array(
'email' => 'orderby2@example.com',
@@ -1054,6 +1067,9 @@ class WC_REST_Customers_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
)
);
+ $this->set_user_registered( $customer1->get_id(), 200 );
+ $this->set_user_registered( $customer2->get_id(), 100 );
+
// Test ordering by ID ascending.
$request = new WP_REST_Request( 'GET', '/wc/v4/customers' );
$request->set_param( 'orderby', 'id' );
@@ -1346,9 +1362,6 @@ class WC_REST_Customers_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
)
);
- // Wait to ensure different registration times.
- sleep( 1 );
-
$customer2 = $this->create_test_customer(
array(
'email' => 'orderbydefault2@example.com',
@@ -1356,8 +1369,6 @@ class WC_REST_Customers_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
)
);
- sleep( 1 );
-
$customer3 = $this->create_test_customer(
array(
'email' => 'orderbydefault3@example.com',
@@ -1365,6 +1376,10 @@ class WC_REST_Customers_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
)
);
+ $this->set_user_registered( $customer1->get_id(), 300 );
+ $this->set_user_registered( $customer2->get_id(), 200 );
+ $this->set_user_registered( $customer3->get_id(), 100 );
+
// Make request without orderby parameter.
$request = new WP_REST_Request( 'GET', '/wc/v4/customers' );
$response = $this->server->dispatch( $request );
@@ -1416,8 +1431,6 @@ class WC_REST_Customers_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
);
update_user_meta( $customer1->get_id(), 'wc_order_count_' . $site_specific_key, 10 );
- sleep( 1 );
-
$customer2 = $this->create_test_customer(
array(
'email' => 'orderbypresent2@example.com',
@@ -1426,8 +1439,6 @@ class WC_REST_Customers_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
);
update_user_meta( $customer2->get_id(), 'wc_order_count_' . $site_specific_key, 25 );
- sleep( 1 );
-
$customer3 = $this->create_test_customer(
array(
'email' => 'orderbypresent3@example.com',
@@ -1530,8 +1541,6 @@ class WC_REST_Customers_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
)
);
- sleep( 1 );
-
$customer2 = $this->create_test_customer(
array(
'email' => 'registered2@example.com',
@@ -1539,8 +1548,6 @@ class WC_REST_Customers_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
)
);
- sleep( 1 );
-
$customer3 = $this->create_test_customer(
array(
'email' => 'registered3@example.com',
@@ -1548,6 +1555,10 @@ class WC_REST_Customers_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
)
);
+ $this->set_user_registered( $customer1->get_id(), 300 );
+ $this->set_user_registered( $customer2->get_id(), 200 );
+ $this->set_user_registered( $customer3->get_id(), 100 );
+
// Test with orderby=registered_date.
$request = new WP_REST_Request( 'GET', '/wc/v4/customers' );
$request->set_param( 'orderby', 'registered_date' );
diff --git a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php
index f585d46763d..659ef9bbef1 100644
--- a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php
+++ b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php
@@ -3224,7 +3224,12 @@ class OrdersTableDataStoreTests extends \HposTestCase {
$this->assertEquals( 'test_value', $r_order->get_meta( 'test_key', true ) );
$different_request && $this->reset_order_data_store_state( $cot_store );
- sleep( 2 );
+
+ // Backdate the modified date on both records (save() backfills the post while sync is on) so the
+ // upcoming sync-off meta update bumps the order's modified date past the post's, without waiting
+ // on the real clock.
+ $r_order->set_date_modified( gmdate( 'Y-m-d H:i:s', strtotime( '-2 day' ) ) );
+ $r_order->save();
$this->disable_cot_sync();
$r_order->update_meta_data( 'test_key', 'test_value_updated' );
diff --git a/plugins/woocommerce/tests/php/src/Internal/OrderReviews/SchedulerTest.php b/plugins/woocommerce/tests/php/src/Internal/OrderReviews/SchedulerTest.php
index d88bab23924..30f86987020 100644
--- a/plugins/woocommerce/tests/php/src/Internal/OrderReviews/SchedulerTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/OrderReviews/SchedulerTest.php
@@ -99,12 +99,23 @@ class SchedulerTest extends WC_Unit_Test_Case {
$order->update_status( 'completed' );
$first = (int) wc_get_order( $order->get_id() )->get_meta( Scheduler::SCHEDULED_META_KEY );
- // Simulate a second completed-notification firing (e.g. status toggled back and forth).
- sleep( 1 );
- do_action( 'woocommerce_order_status_completed', $order->get_id() ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment -- existing core hook, fired here only to simulate a duplicate transition in the test.
+ // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment -- Existing core hook, fired here only to simulate a second completed-notification (e.g. status toggled back and forth).
+ do_action( 'woocommerce_order_status_completed', $order->get_id() );
$second = (int) wc_get_order( $order->get_id() )->get_meta( Scheduler::SCHEDULED_META_KEY );
$this->assertSame( $first, $second, 'Scheduled-at meta should not change on re-completion.' );
+ $this->assertCount(
+ 1,
+ as_get_scheduled_actions(
+ array(
+ 'hook' => Scheduler::ACTION_HOOK,
+ 'args' => array( $order->get_id() ),
+ 'status' => \ActionScheduler_Store::STATUS_PENDING,
+ ),
+ 'ids'
+ ),
+ 'A duplicate completion must not schedule a second review-request action.'
+ );
}
/**