From 3dc25249a4758934cdd6d9e1ed79cd95b0e7a3b4 Mon Sep 17 00:00:00 2001 From: Paul Bearne Date: Wed, 13 May 2026 15:04:36 -0400 Subject: [PATCH 1/4] Tests: Add unit tests for wp_ajax_fetch_list() Co-authored-by: Junie --- .../includes/ajax-actions/wpAjaxFetchList.php | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php diff --git a/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php b/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php new file mode 100644 index 0000000000000..2dc24c73726fe --- /dev/null +++ b/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php @@ -0,0 +1,173 @@ +_setRole( 'administrator' ); + + // Set up the $_GET request. + $list_class = 'WP_Posts_List_Table'; + $_GET = array( + 'list_args' => array( + 'class' => $list_class, + 'screen' => array( + 'id' => 'edit-post', + ), + ), + '_ajax_fetch_list_nonce' => wp_create_nonce( "fetch-list-$list_class" ), + ); + + // Make the request. + try { + $this->_handleAjax( 'fetch-list' ); + } catch ( WPAjaxDieContinueException $e ) { + // Expected exception. + unset( $e ); + } catch ( WPAjaxDieStopException $e ) { + // Expected exception. + unset( $e ); + } catch ( Exception $e ) { + $this->fail( 'Unexpected exception: ' . $e->getMessage() ); + } + + if ( empty( $this->_last_response ) ) { + $this->fail( 'Ajax response was empty' ); + } + + $response = json_decode( $this->_last_response, true ); + + $this->assertIsArray( $response ); + $this->assertArrayHasKey( 'rows', $response ); + $this->assertStringContainsString( 'No posts found.', $response['rows'] ); + } + + /** + * Tests fetching a list table with items. + * + * @ticket 65237 + */ + public function test_wp_ajax_fetch_list_with_items(): void { + $this->_setRole( 'administrator' ); + + // Create a post. + self::factory()->post->create( array( 'post_title' => 'Test Post' ) ); + + $list_class = 'WP_Posts_List_Table'; + $_GET = array( + 'list_args' => array( + 'class' => $list_class, + 'screen' => array( + 'id' => 'edit-post', + ), + ), + '_ajax_fetch_list_nonce' => wp_create_nonce( "fetch-list-$list_class" ), + ); + + try { + $this->_handleAjax( 'fetch-list' ); + } catch ( WPAjaxDieContinueException $e ) { + unset( $e ); + } catch ( WPAjaxDieStopException $e ) { + unset( $e ); + } + + $response = json_decode( $this->_last_response, true ); + + $this->assertIsArray( $response ); + $this->assertArrayHasKey( 'rows', $response ); + $this->assertStringContainsString( 'Test Post', $response['rows'] ); + $this->assertSame( '1 item', $response['total_items_i18n'] ); + } + + /** + * Tests fetching a list table with an invalid nonce. + * + * @ticket 65237 + */ + public function test_wp_ajax_fetch_list_invalid_nonce(): void { + $this->_setRole( 'administrator' ); + + $list_class = 'WP_Posts_List_Table'; + $_GET = array( + 'list_args' => array( + 'class' => $list_class, + ), + '_ajax_fetch_list_nonce' => 'invalid-nonce', + ); + + $this->expectException( 'WPAjaxDieStopException' ); + $this->expectExceptionMessage( '-1' ); + + $this->_handleAjax( 'fetch-list' ); + } + + /** + * Tests fetching a list table with an invalid class. + * + * @ticket 65237 + */ + public function test_wp_ajax_fetch_list_invalid_class(): void { + $this->_setRole( 'administrator' ); + + $list_class = 'Invalid_List_Table'; + $_GET = array( + 'list_args' => array( + 'class' => $list_class, + ), + '_ajax_fetch_list_nonce' => wp_create_nonce( "fetch-list-$list_class" ), + ); + + $this->expectException( 'WPAjaxDieStopException' ); + $this->expectExceptionMessage( '0' ); + + $this->_handleAjax( 'fetch-list' ); + } + + /** + * Tests fetching a list table as an unprivileged user. + * + * @ticket 65237 + */ + public function test_wp_ajax_fetch_list_unprivileged_user(): void { + // Become a subscriber. + $this->_setRole( 'subscriber' ); + + $list_class = 'WP_Posts_List_Table'; + $_GET = array( + 'list_args' => array( + 'class' => $list_class, + 'screen' => array( + 'id' => 'edit-post', + ), + ), + '_ajax_fetch_list_nonce' => wp_create_nonce( "fetch-list-$list_class" ), + ); + + $this->expectException( 'WPAjaxDieStopException' ); + $this->expectExceptionMessage( '-1' ); + + $this->_handleAjax( 'fetch-list' ); + } +} From f31e03a56336c3129a617124a8427d3c1e1aa74e Mon Sep 17 00:00:00 2001 From: Paul Bearne Date: Wed, 13 May 2026 15:40:15 -0400 Subject: [PATCH 2/4] Tests: Improve code alignment in wp_ajax_fetch_list() unit tests. --- .../includes/ajax-actions/wpAjaxFetchList.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php b/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php index 2dc24c73726fe..6cb132090c9c8 100644 --- a/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php +++ b/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php @@ -29,8 +29,8 @@ public function test_wp_ajax_fetch_list(): void { // Set up the $_GET request. $list_class = 'WP_Posts_List_Table'; - $_GET = array( - 'list_args' => array( + $_GET = array( + 'list_args' => array( 'class' => $list_class, 'screen' => array( 'id' => 'edit-post', @@ -75,8 +75,8 @@ public function test_wp_ajax_fetch_list_with_items(): void { self::factory()->post->create( array( 'post_title' => 'Test Post' ) ); $list_class = 'WP_Posts_List_Table'; - $_GET = array( - 'list_args' => array( + $_GET = array( + 'list_args' => array( 'class' => $list_class, 'screen' => array( 'id' => 'edit-post', @@ -110,7 +110,7 @@ public function test_wp_ajax_fetch_list_invalid_nonce(): void { $this->_setRole( 'administrator' ); $list_class = 'WP_Posts_List_Table'; - $_GET = array( + $_GET = array( 'list_args' => array( 'class' => $list_class, ), @@ -132,7 +132,7 @@ public function test_wp_ajax_fetch_list_invalid_class(): void { $this->_setRole( 'administrator' ); $list_class = 'Invalid_List_Table'; - $_GET = array( + $_GET = array( 'list_args' => array( 'class' => $list_class, ), @@ -155,8 +155,8 @@ public function test_wp_ajax_fetch_list_unprivileged_user(): void { $this->_setRole( 'subscriber' ); $list_class = 'WP_Posts_List_Table'; - $_GET = array( - 'list_args' => array( + $_GET = array( + 'list_args' => array( 'class' => $list_class, 'screen' => array( 'id' => 'edit-post', From f518e4d317fe3143a32033ce0add94606e79fb62 Mon Sep 17 00:00:00 2001 From: Paul Bearne Date: Thu, 14 May 2026 16:52:52 -0400 Subject: [PATCH 3/4] Tests: Add unit tests for wp_ajax_logged_in() --- .../includes/ajax-actions/wpAjaxLoggedIn.php | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxLoggedIn.php diff --git a/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxLoggedIn.php b/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxLoggedIn.php new file mode 100644 index 0000000000000..4a187b1bf7c37 --- /dev/null +++ b/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxLoggedIn.php @@ -0,0 +1,72 @@ +_setRole( 'subscriber' ); + + // Set up the request. + $_REQUEST['action'] = 'logged-in'; + + // Make the request. + try { + $this->_handleAjax( 'logged-in' ); + } catch ( WPAjaxDieContinueException $e ) { + // Expected exception. + unset( $e ); + } catch ( WPAjaxDieStopException $e ) { + $this->_last_response = $e->getMessage(); + } + + // The response should be 1. + $this->assertSame( '1', $this->_last_response, 'The response should be 1 for logged-in users' ); + } + + /** + * Tests the logged-in AJAX action as a logged-out user. + * + * @ticket 65242 + */ + public function test_wp_ajax_logged_in_logged_out(): void { + // Log out. + wp_set_current_user( 0 ); + + // Set up the request. + $_REQUEST['action'] = 'logged-in'; + + // In a real scenario, admin-ajax.php would not fire wp_ajax_logged-in for logged-out users. + // Since _handleAjax simulates the hook firing directly, we test that the handler itself + // (if it had permission checks) would fail. + // However, wp_ajax_logged_in() has NO permission checks because it relies on admin-ajax.php. + + // To test the "logged-out" behavior properly, we should verify it DOES NOT have a nopriv handler. + $this->assertFalse( has_action( 'wp_ajax_nopriv_logged-in' ), 'Should not have a nopriv handler' ); + } +} From 59bc3a8b5454ef01c7b632a229b405a46f8c824e Mon Sep 17 00:00:00 2001 From: Paul Bearne Date: Thu, 14 May 2026 16:54:58 -0400 Subject: [PATCH 4/4] Delete tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php --- .../includes/ajax-actions/wpAjaxFetchList.php | 173 ------------------ 1 file changed, 173 deletions(-) delete mode 100644 tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php diff --git a/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php b/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php deleted file mode 100644 index 6cb132090c9c8..0000000000000 --- a/tests/phpunit/tests/admin/includes/ajax-actions/wpAjaxFetchList.php +++ /dev/null @@ -1,173 +0,0 @@ -_setRole( 'administrator' ); - - // Set up the $_GET request. - $list_class = 'WP_Posts_List_Table'; - $_GET = array( - 'list_args' => array( - 'class' => $list_class, - 'screen' => array( - 'id' => 'edit-post', - ), - ), - '_ajax_fetch_list_nonce' => wp_create_nonce( "fetch-list-$list_class" ), - ); - - // Make the request. - try { - $this->_handleAjax( 'fetch-list' ); - } catch ( WPAjaxDieContinueException $e ) { - // Expected exception. - unset( $e ); - } catch ( WPAjaxDieStopException $e ) { - // Expected exception. - unset( $e ); - } catch ( Exception $e ) { - $this->fail( 'Unexpected exception: ' . $e->getMessage() ); - } - - if ( empty( $this->_last_response ) ) { - $this->fail( 'Ajax response was empty' ); - } - - $response = json_decode( $this->_last_response, true ); - - $this->assertIsArray( $response ); - $this->assertArrayHasKey( 'rows', $response ); - $this->assertStringContainsString( 'No posts found.', $response['rows'] ); - } - - /** - * Tests fetching a list table with items. - * - * @ticket 65237 - */ - public function test_wp_ajax_fetch_list_with_items(): void { - $this->_setRole( 'administrator' ); - - // Create a post. - self::factory()->post->create( array( 'post_title' => 'Test Post' ) ); - - $list_class = 'WP_Posts_List_Table'; - $_GET = array( - 'list_args' => array( - 'class' => $list_class, - 'screen' => array( - 'id' => 'edit-post', - ), - ), - '_ajax_fetch_list_nonce' => wp_create_nonce( "fetch-list-$list_class" ), - ); - - try { - $this->_handleAjax( 'fetch-list' ); - } catch ( WPAjaxDieContinueException $e ) { - unset( $e ); - } catch ( WPAjaxDieStopException $e ) { - unset( $e ); - } - - $response = json_decode( $this->_last_response, true ); - - $this->assertIsArray( $response ); - $this->assertArrayHasKey( 'rows', $response ); - $this->assertStringContainsString( 'Test Post', $response['rows'] ); - $this->assertSame( '1 item', $response['total_items_i18n'] ); - } - - /** - * Tests fetching a list table with an invalid nonce. - * - * @ticket 65237 - */ - public function test_wp_ajax_fetch_list_invalid_nonce(): void { - $this->_setRole( 'administrator' ); - - $list_class = 'WP_Posts_List_Table'; - $_GET = array( - 'list_args' => array( - 'class' => $list_class, - ), - '_ajax_fetch_list_nonce' => 'invalid-nonce', - ); - - $this->expectException( 'WPAjaxDieStopException' ); - $this->expectExceptionMessage( '-1' ); - - $this->_handleAjax( 'fetch-list' ); - } - - /** - * Tests fetching a list table with an invalid class. - * - * @ticket 65237 - */ - public function test_wp_ajax_fetch_list_invalid_class(): void { - $this->_setRole( 'administrator' ); - - $list_class = 'Invalid_List_Table'; - $_GET = array( - 'list_args' => array( - 'class' => $list_class, - ), - '_ajax_fetch_list_nonce' => wp_create_nonce( "fetch-list-$list_class" ), - ); - - $this->expectException( 'WPAjaxDieStopException' ); - $this->expectExceptionMessage( '0' ); - - $this->_handleAjax( 'fetch-list' ); - } - - /** - * Tests fetching a list table as an unprivileged user. - * - * @ticket 65237 - */ - public function test_wp_ajax_fetch_list_unprivileged_user(): void { - // Become a subscriber. - $this->_setRole( 'subscriber' ); - - $list_class = 'WP_Posts_List_Table'; - $_GET = array( - 'list_args' => array( - 'class' => $list_class, - 'screen' => array( - 'id' => 'edit-post', - ), - ), - '_ajax_fetch_list_nonce' => wp_create_nonce( "fetch-list-$list_class" ), - ); - - $this->expectException( 'WPAjaxDieStopException' ); - $this->expectExceptionMessage( '-1' ); - - $this->_handleAjax( 'fetch-list' ); - } -}