From 1859613af2f2ad0aa4ad36d57ec90666375e3773 Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Wed, 14 Aug 2024 16:05:02 +0530 Subject: [PATCH 1/4] Add tests that fails in current codebase --- plugins/auto-sizes/tests/test-auto-sizes.php | 93 ++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/plugins/auto-sizes/tests/test-auto-sizes.php b/plugins/auto-sizes/tests/test-auto-sizes.php index 037820331f..bb36d1861d 100644 --- a/plugins/auto-sizes/tests/test-auto-sizes.php +++ b/plugins/auto-sizes/tests/test-auto-sizes.php @@ -218,4 +218,97 @@ public function test_auto_sizes_render_generator(): void { $this->assertStringContainsString( 'generator', $tag ); $this->assertStringContainsString( 'auto-sizes ' . IMAGE_AUTO_SIZES_VERSION, $tag ); } + + public function test_content_image_with_single_quote_replacement_does_not_have_auto_sizes(): void { + add_filter( + 'get_image_tag', + static function ( $html ) { + return str_replace( + '" />', + '" loading="lazy" sizes="(max-width: 1024px) 100vw, 1024px" />', + $html + ); + } + ); + + $image_tag = str_replace( '"', "'", $this->get_image_tag( self::$image_id ) ); + $image_content = wp_filter_content_tags( $image_tag ); + + $processor = new WP_HTML_Tag_Processor( $image_content ); + $this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' ); + $sizes = $processor->get_attribute( 'sizes' ); + $this->assertTrue( auto_sizes_attribute_includes_valid_auto( $sizes ), 'The sizes attribute does not include "auto" as the first item in the list.' ); + $this->assertStringContainsString( 'auto', $sizes, 'The sizes attribute does not contain "auto".' ); + } + + public function test_content_image_with_custom_attribute_name_with_sizes_at_the_end_does_not_have_auto_sizes(): void { + add_filter( + 'get_image_tag', + static function ( $html ) { + return str_replace( + '" />', + '" loading="lazy" sizes="(max-width: 1024px) 100vw, 1024px" data-tshirt-sizes="S M L" />', + $html + ); + } + ); + + $image_tag = $this->get_image_tag( self::$image_id ); + $image_content = wp_filter_content_tags( $image_tag ); + + $processor = new WP_HTML_Tag_Processor( $image_content ); + $this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' ); + $data_tshirt_sizes = $processor->get_attribute( 'data-tshirt-sizes' ); + $this->assertStringNotContainsString( 'auto', $data_tshirt_sizes, 'The data-tshirt-sizes attribute should not contain "auto".' ); + $this->assertSame( 'S M L', $data_tshirt_sizes, 'The data-tshirt-sizes attribute does not match the expected value.' ); + } + + public function test_content_image_with_lazy_load_text_in_alt_does_not_have_auto_sizes(): void { + add_filter( + 'get_image_tag', + static function ( $html ) { + return str_replace( + 'alt="', + 'alt="This is the LCP image and it should not get loading="lazy"!', + $html + ); + } + ); + + $image_tag = $this->get_image_tag( self::$image_id ); + $image_content = wp_filter_content_tags( $image_tag ); + + $processor = new WP_HTML_Tag_Processor( $image_content ); + $this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' ); + $this->assertNull( $processor->get_attribute( 'loading' ), 'The loading attribute should be null when lazy-load text is in the alt attribute.' ); + $sizes = $processor->get_attribute( 'sizes' ); + $this->assertFalse( auto_sizes_attribute_includes_valid_auto( $sizes ), 'The sizes attribute does not include "auto" as the first item in the list.' ); + $this->assertStringNotContainsString( 'auto', $sizes, 'The sizes attribute should not contain "auto".' ); + } + + public function test_content_image_with_custom_attribute_name_with_loading_lazy_at_the_end_does_not_have_auto_sizes(): void { + // Force lazy loading attribute. + add_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); + + add_filter( + 'get_image_tag', + static function ( $html ) { + return str_replace( + '" />', + '" data-removed-loading="lazy" />', + $html + ); + } + ); + + $image_tag = $this->get_image_tag( self::$image_id ); + $image_content = wp_filter_content_tags( $image_tag ); + + $processor = new WP_HTML_Tag_Processor( $image_content ); + $this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' ); + $this->assertNull( $processor->get_attribute( 'loading' ), 'The loading attribute should be null when a custom attribute name is used.' ); + $sizes = $processor->get_attribute( 'sizes' ); + $this->assertFalse( auto_sizes_attribute_includes_valid_auto( $sizes ), 'The sizes attribute does not include "auto" as the first item in the list.' ); + $this->assertStringNotContainsString( 'auto', $sizes, 'The sizes attribute should not contain "auto".' ); + } } From 32b9abc15b847d711bd61219f112f90e5dc95c96 Mon Sep 17 00:00:00 2001 From: Mukesh Panchal Date: Wed, 14 Aug 2024 16:22:03 +0530 Subject: [PATCH 2/4] Use WP_HTML_Tag_Processor in auto_sizes_update_content_img_tag --- plugins/auto-sizes/hooks.php | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/plugins/auto-sizes/hooks.php b/plugins/auto-sizes/hooks.php index a3508c6d78..5bb6beee12 100644 --- a/plugins/auto-sizes/hooks.php +++ b/plugins/auto-sizes/hooks.php @@ -57,24 +57,32 @@ function auto_sizes_update_content_img_tag( $html ): string { $html = ''; } + $processor = new WP_HTML_Tag_Processor( $html ); + + // Bail if there is no IMG tag. + if ( ! $processor->next_tag( array( 'tag_name' => 'IMG' ) ) ) { + return $html; + } + // Bail early if the image is not lazy-loaded. - if ( false === strpos( $html, 'loading="lazy"' ) ) { + if ( 'lazy' !== $processor->get_attribute( 'loading' ) ) { return $html; } + $sizes = $processor->get_attribute( 'sizes' ); + // Bail early if the image is not responsive. - if ( 1 !== preg_match( '/sizes="([^"]+)"/', $html, $match ) ) { + if ( ! is_string( $sizes ) ) { return $html; } // Don't add 'auto' to the sizes attribute if it already exists. - if ( auto_sizes_attribute_includes_valid_auto( $match[1] ) ) { + if ( auto_sizes_attribute_includes_valid_auto( $sizes ) ) { return $html; } - $html = str_replace( 'sizes="', 'sizes="auto, ', $html ); - - return $html; + $processor->set_attribute( 'sizes', "auto, $sizes" ); + return $processor->get_updated_html(); } add_filter( 'wp_content_img_tag', 'auto_sizes_update_content_img_tag' ); From 6433721ed72cc3126542385475370d6add09bb17 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 15 Aug 2024 13:33:30 -0700 Subject: [PATCH 3/4] Remove unused variable --- plugins/auto-sizes/tests/test-auto-sizes.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/auto-sizes/tests/test-auto-sizes.php b/plugins/auto-sizes/tests/test-auto-sizes.php index bb36d1861d..5f67a5348e 100644 --- a/plugins/auto-sizes/tests/test-auto-sizes.php +++ b/plugins/auto-sizes/tests/test-auto-sizes.php @@ -71,8 +71,6 @@ public function test_content_image_with_lazy_loading_has_auto_sizes(): void { // Force lazy loading attribute. add_filter( 'wp_img_tag_add_loading_attr', '__return_true' ); - $image_tag = $this->get_image_tag( self::$image_id ); - $this->assertStringContainsString( 'sizes="auto, (max-width: 1024px) 100vw, 1024px"', wp_filter_content_tags( $this->get_image_tag( self::$image_id ) ) From c5de91c091cc47f1770cf03dd427ba622472e125 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 15 Aug 2024 13:58:43 -0700 Subject: [PATCH 4/4] Account for upper-case loading attribute and with whitespace padding Refactor test cases to use snapshots --- plugins/auto-sizes/hooks.php | 3 +- plugins/auto-sizes/tests/test-auto-sizes.php | 140 +++++++------------ 2 files changed, 55 insertions(+), 88 deletions(-) diff --git a/plugins/auto-sizes/hooks.php b/plugins/auto-sizes/hooks.php index 5bb6beee12..41b653e457 100644 --- a/plugins/auto-sizes/hooks.php +++ b/plugins/auto-sizes/hooks.php @@ -65,7 +65,8 @@ function auto_sizes_update_content_img_tag( $html ): string { } // Bail early if the image is not lazy-loaded. - if ( 'lazy' !== $processor->get_attribute( 'loading' ) ) { + $value = $processor->get_attribute( 'loading' ); + if ( ! is_string( $value ) || 'lazy' !== strtolower( trim( $value, " \t\f\r\n" ) ) ) { return $html; } diff --git a/plugins/auto-sizes/tests/test-auto-sizes.php b/plugins/auto-sizes/tests/test-auto-sizes.php index 5f67a5348e..13898a4ae9 100644 --- a/plugins/auto-sizes/tests/test-auto-sizes.php +++ b/plugins/auto-sizes/tests/test-auto-sizes.php @@ -217,96 +217,62 @@ public function test_auto_sizes_render_generator(): void { $this->assertStringContainsString( 'auto-sizes ' . IMAGE_AUTO_SIZES_VERSION, $tag ); } - public function test_content_image_with_single_quote_replacement_does_not_have_auto_sizes(): void { - add_filter( - 'get_image_tag', - static function ( $html ) { - return str_replace( - '" />', - '" loading="lazy" sizes="(max-width: 1024px) 100vw, 1024px" />', - $html - ); - } - ); - - $image_tag = str_replace( '"', "'", $this->get_image_tag( self::$image_id ) ); - $image_content = wp_filter_content_tags( $image_tag ); - - $processor = new WP_HTML_Tag_Processor( $image_content ); - $this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' ); - $sizes = $processor->get_attribute( 'sizes' ); - $this->assertTrue( auto_sizes_attribute_includes_valid_auto( $sizes ), 'The sizes attribute does not include "auto" as the first item in the list.' ); - $this->assertStringContainsString( 'auto', $sizes, 'The sizes attribute does not contain "auto".' ); - } - - public function test_content_image_with_custom_attribute_name_with_sizes_at_the_end_does_not_have_auto_sizes(): void { - add_filter( - 'get_image_tag', - static function ( $html ) { - return str_replace( - '" />', - '" loading="lazy" sizes="(max-width: 1024px) 100vw, 1024px" data-tshirt-sizes="S M L" />', - $html - ); - } - ); - - $image_tag = $this->get_image_tag( self::$image_id ); - $image_content = wp_filter_content_tags( $image_tag ); - - $processor = new WP_HTML_Tag_Processor( $image_content ); - $this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' ); - $data_tshirt_sizes = $processor->get_attribute( 'data-tshirt-sizes' ); - $this->assertStringNotContainsString( 'auto', $data_tshirt_sizes, 'The data-tshirt-sizes attribute should not contain "auto".' ); - $this->assertSame( 'S M L', $data_tshirt_sizes, 'The data-tshirt-sizes attribute does not match the expected value.' ); - } - - public function test_content_image_with_lazy_load_text_in_alt_does_not_have_auto_sizes(): void { - add_filter( - 'get_image_tag', - static function ( $html ) { - return str_replace( - 'alt="', - 'alt="This is the LCP image and it should not get loading="lazy"!', - $html - ); - } + /** + * @return array + */ + public function data_provider_to_test_auto_sizes_update_content_img_tag(): array { + return array( + 'expected_with_single_quoted_attributes' => array( + 'input' => "", + 'expected' => "", + ), + 'expected_with_data_sizes_attribute' => array( + 'input' => '', + 'expected' => '', + ), + 'expected_with_data_sizes_attribute_already_present' => array( + 'input' => '', + 'expected' => '', + ), + 'not_expected_with_loading_lazy_in_attr_value' => array( + 'input' => '\'This', + 'expected' => '\'This', + ), + 'not_expected_with_data_loading_attribute_present' => array( + 'input' => '', + 'expected' => '', + ), + 'expected_when_attributes_have_spaces_after_them' => array( + 'input' => '', + 'expected' => '', + ), + 'expected_when_attributes_are_upper_case' => array( + 'input' => '', + 'expected' => '', + ), + 'expected_when_loading_lazy_lacks_quotes' => array( + 'input' => '', + 'expected' => '', + ), + 'expected_when_loading_lazy_has_whitespace' => array( + 'input' => '', + 'expected' => '', + ), + 'not_expected_when_sizes_auto_lacks_quotes' => array( + 'input' => '', + 'expected' => '', + ), ); - - $image_tag = $this->get_image_tag( self::$image_id ); - $image_content = wp_filter_content_tags( $image_tag ); - - $processor = new WP_HTML_Tag_Processor( $image_content ); - $this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' ); - $this->assertNull( $processor->get_attribute( 'loading' ), 'The loading attribute should be null when lazy-load text is in the alt attribute.' ); - $sizes = $processor->get_attribute( 'sizes' ); - $this->assertFalse( auto_sizes_attribute_includes_valid_auto( $sizes ), 'The sizes attribute does not include "auto" as the first item in the list.' ); - $this->assertStringNotContainsString( 'auto', $sizes, 'The sizes attribute should not contain "auto".' ); } - public function test_content_image_with_custom_attribute_name_with_loading_lazy_at_the_end_does_not_have_auto_sizes(): void { - // Force lazy loading attribute. - add_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); - - add_filter( - 'get_image_tag', - static function ( $html ) { - return str_replace( - '" />', - '" data-removed-loading="lazy" />', - $html - ); - } + /** + * @covers ::auto_sizes_update_content_img_tag + * @dataProvider data_provider_to_test_auto_sizes_update_content_img_tag + */ + public function test_auto_sizes_update_content_img_tag( string $input, string $expected ): void { + $this->assertSame( + $expected, + auto_sizes_update_content_img_tag( $input ) ); - - $image_tag = $this->get_image_tag( self::$image_id ); - $image_content = wp_filter_content_tags( $image_tag ); - - $processor = new WP_HTML_Tag_Processor( $image_content ); - $this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' ); - $this->assertNull( $processor->get_attribute( 'loading' ), 'The loading attribute should be null when a custom attribute name is used.' ); - $sizes = $processor->get_attribute( 'sizes' ); - $this->assertFalse( auto_sizes_attribute_includes_valid_auto( $sizes ), 'The sizes attribute does not include "auto" as the first item in the list.' ); - $this->assertStringNotContainsString( 'auto', $sizes, 'The sizes attribute should not contain "auto".' ); } }