Make WordPress Core

Opened 10 years ago

Last modified 8 weeks ago

#37207 new defect (bug)

Multiple unit tests for add_rewrite_endpoint lose custom endpoints

Reported by: ericdaams Owned by:
Priority: normal Milestone: Future Release
Component: Build/Test Tools Version: 4.5.3
Severity: normal Keywords: has-patch has-unit-tests
Cc: Focuses:

Description

When registering multiple endpoints through add_rewrite_endpoint(), tests for the existence of each endpoint in $GLOBALS['wp']->public_query_vars fails.

I have attached a simple plugin that illustrates the problem. Steps to reproduce:

  1. Download the plugin.
  2. Run phpunit inside of it.
  3. Test #1 succeeds while test #2 fails.

The relevant excerpts from the plugin are included below.

Endpoint registration:

add_action( 'init', function() {
	add_rewrite_endpoint( 'custom-endpoint', EP_ROOT );
	add_rewrite_endpoint( 'custom-endpoint-2', EP_ROOT );
});

Tests:

class TestRewriteEndpoint extends WP_UnitTestCase {
	public function setUp() {
		parent::setUp();
		$this->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' );
		$this->qvs = $GLOBALS['wp']->public_query_vars;
		// print_r( $this->qvs );
	}
	public function tearDown() {
		$GLOBALS['wp']->public_query_vars = $this->qvs;
		parent::tearDown();
	}
	public function test_is_custom_endpoint_added() {
		$this->assertContains( 'custom-endpoint', $GLOBALS['wp']->public_query_vars );
	}
	public function test_is_custom_endpoint_2_added() {
		$this->assertContains( 'custom-endpoint-2', $GLOBALS['wp']->public_query_vars );
	}
}

This may possibly be related to #34346, though in this case I am not using go_to().

Attachments (3)

wp-unit-testing-add-rewrite-endpoint-bug-master.zip​ (4.8 KB ) - added by ericdaams 10 years ago.
37207.diff​ (1.6 KB ) - added by mboynes 10 years ago.
Store $wp's query vars after bootstrap to restore on tearDown
37207.2.diff​ (1.6 KB ) - added by mboynes 10 years ago.
Only restore query vars if not running core unit tests

Download all attachments as: .zip

Change History (10)

#1 @mboynes
10 years ago

I ran across this issue today.

In short, it's common practice to call add_rewrite_tag() or add_rewrite_endpoint() on init. These add public query vars to $GLOBALS['wp'] directly (not via the query_vars filter). init fires once on load during a run of phpunit, not once per test. In WP_UnitTestCase::tearDown(), $GLOBALS['wp'] is completely reset, which includes wiping the public query vars. Because init is never run again, those query vars are never added back.

One potential solution would be to store query vars at the end of the bootstrap, then reset them in WP_UnitTestCase::tearDown() after $GLOBALS['wp'] is reset. It would be important to store them on bootstrap and not WP_UnitTestCase::setUp() so that query vars added during one test don't persist to the next test.

#2 @boonebgorges
10 years ago

  • Keywords needs-patch added
  • Milestone Awaiting Review → Future Release

One potential solution would be to store query vars at the end of the bootstrap

Something like this seems like the right approach to me.

@mboynes
10 years ago

Store $wp's query vars after bootstrap to restore on tearDown

#3 @mboynes
10 years ago

Potential solution proposed in 37207.diff

#4 @boonebgorges
10 years ago

@mboynes Thanks for the patch. I'm looking it over in more detail, and now I wonder whether it's the right approach.

Consider post types, taxonomies, and post statuses. In each case, it's common practice for plugins to register these object types on init. In #29827, we toyed with a couple different solutions, and it turned out to introduce weird leakage bugs if we tried to back up and then restore global data like this. So we went with [29869], which basically says: when running the *core* tests, the post_type/taxonomy/post_status slate should be wiped clean between tests, but these globals should not be touched between tests when WP_UnitTestCase is called by a plugin.

I'm not certain that this setup is the "best" in any meaningful sense, but it seems like a compromise that's worked for us. Could we consider something similar here? Roughly: the backup/reset process would only happen if ! WP_RUN_CORE_TEST. @mboynes @ericdaams What do you think?

#5 @mboynes
10 years ago

@boonebgorges that approach makes sense to me. I'll update the patch.

@mboynes
10 years ago

Only restore query vars if not running core unit tests

This ticket was mentioned in ​PR #12730 on ​WordPress/wordpress-develop by ​@arkaprabhachowdhury.


3 months ago
#6

  • Keywords has-patch has-unit-tests added; needs-patch removed

Preserves public query variables registered by plugins during bootstrap when the WordPress test suite runs in non-core mode. This prevents endpoints registered on init from disappearing after the first test while retaining the existing reset behavior for core tests.

Adds regression coverage across the actual test teardown boundary.

## Testing

  • Focused rewrite endpoint suite: 10 tests, 19 assertions
  • Ticket group: 2 tests, 2 assertions
  • External plugin-mode reproduction: 2 tests, 2 assertions
  • PHP syntax checks
  • PHPCBF and PHPCS
  • git diff --check

## Use of AI Tools

AI assistance: Yes
Tool(s): OpenAI Codex
Model(s): GPT-5
Used for: Ticket investigation, implementation, regression tests, and local validation; the resulting diff and test output were reviewed before publication.

#7 @arkaprabhachowdhury
8 weeks ago

Opened [PR #12730](​https://github.com/WordPress/wordpress-develop/pull/12730) to address this ticket. Preserves public query variables registered by plugins during bootstrap when the WordPress test suite runs in non-core mode. This prevents endpoints registered on init from disappearing after the first test while retaining the existing reset behavior for core tests. Adds regression coverage across the actual test teardown boundary. Testing - Focused rewrite endpoint suite: 10 tests, 19 assertions - Ticket group: 2 tests, 2 assertions - External plugin-mode reproduction: 2 tests, 2 assertions - P The PR includes focused regression coverage, and its validation details are recorded in the PR description.

I picked this up because the ticket describes a concrete core behavior or edge case that remains relevant in current WordPress. The proposed change is intentionally scoped to the ticket and is submitted here for code review, with the technical discussion remaining on this ticket.

Note: See TracTickets for help on using tickets.