From 751b1b23acd4ffecf037f891ce4e5634dd791a4d Mon Sep 17 00:00:00 2001 From: wppoland Date: Sun, 9 Aug 2026 16:37:03 +0200 Subject: [PATCH] HTML API: Add a serialization regression test for enqueued attribute updates. [62960] made get_attribute_names_with_prefix() respect enqueued updates, but its tests only cover WP_HTML_Tag_Processor. WP_HTML_Processor::serialize_token() consumed the same stale name list while reading values through get_attribute(), so a removed attribute was re-emitted as a value-less attribute and an added one was dropped. That path gained no coverage. Fails at [62960]^ with '
', passes on trunk. See #64567. --- .../html-api/wpHtmlProcessor-serialize.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php index 1ce8855305ae9..a4502c531c6ef 100644 --- a/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php +++ b/tests/phpunit/tests/html-api/wpHtmlProcessor-serialize.php @@ -853,4 +853,39 @@ public static function data_provider_normalize_special_leading_newline_cases(): ), ); } + + /** + * Ensures that serialize_token() reflects enqueued attribute updates instead + * of emitting removed attributes as value-less attributes or omitting added ones. + * + * serialize_token() iterates the names from get_attribute_names_with_prefix( '' ) + * but reads each value through get_attribute(). Before #64567 the name list did not + * reflect enqueued updates while the values did, so a removed attribute survived in + * the output as a boolean attribute and an added attribute was dropped entirely. + * + * @ticket 64567 + * + * @covers WP_HTML_Processor::serialize_token + */ + public function test_serialize_token_reflects_enqueued_attribute_updates() { + $processor = WP_HTML_Processor::create_fragment( '
Text
' ); + $processor->next_tag(); + $processor->remove_attribute( 'onclick' ); + + $this->assertSame( + '
', + $processor->serialize_token(), + 'An attribute enqueued for removal was serialized as a value-less attribute.' + ); + + $processor = WP_HTML_Processor::create_fragment( '
Text
' ); + $processor->next_tag(); + $processor->set_attribute( 'id', 'new' ); + + $this->assertStringContainsString( + 'id="new"', + $processor->serialize_token(), + 'An attribute enqueued via set_attribute() was not serialized.' + ); + } }