@@ -28,6 +28,32 @@ public function setUp(): void {
2828 add_filter ( 'pre_http_request ' , array ( $ this , 'mock_http_requests ' ), 10 , 3 );
2929 }
3030
31+ /**
32+ * Test that the far-future headers test is added to the site health tests.
33+ *
34+ * @covers ::perflab_ffh_add_test
35+ */
36+ public function test_perflab_ffh_add_test (): void {
37+ $ tests = array (
38+ 'direct ' => array (),
39+ );
40+
41+ $ tests = perflab_ffh_add_test ( $ tests );
42+
43+ $ this ->assertArrayHasKey ( 'far_future_headers ' , $ tests ['direct ' ] );
44+ $ this ->assertEquals ( 'Effective Caching Headers ' , $ tests ['direct ' ]['far_future_headers ' ]['label ' ] );
45+ $ this ->assertEquals ( 'perflab_ffh_assets_test ' , $ tests ['direct ' ]['far_future_headers ' ]['test ' ] );
46+ }
47+
48+ /**
49+ * Test that the far-future headers test is attached to the site status tests.
50+ *
51+ * @covers ::perflab_ffh_add_test
52+ */
53+ public function test_perflab_ffh_add_test_is_attached_to_site_status_tests (): void {
54+ $ this ->assertNotFalse ( has_filter ( 'site_status_tests ' , 'perflab_ffh_add_test ' ) );
55+ }
56+
3157 /**
3258 * Test that when all assets have valid far-future headers, the status is "good".
3359 *
@@ -61,24 +87,85 @@ public function test_all_assets_valid_far_future_headers(): void {
6187 public function test_assets_conditionally_cached (): void {
6288 // For conditional caching scenario, setting etag/last-modified headers.
6389 $ this ->mocked_responses = array (
64- 'js/wp-embed.min.js ' => $ this ->build_response ( 200 , array ( 'cache-control ' => 'max-age= ' . ( YEAR_IN_SECONDS + 1000 ) ) ),
65- 'css/buttons.min.css ' => $ this ->build_response ( 200 , array ( 'etag ' => '"123456789" ' ) ),
66- 'fonts/dashicons.woff2 ' => $ this ->build_response ( 200 , array ( 'last-modified ' => gmdate ( 'D, d M Y H:i:s ' , time () - 1000 ) . ' GMT ' ) ),
67- 'images/media/video.png ' => $ this ->build_response (
90+ includes_url ( 'js/wp-embed.min.js ' ) => $ this ->build_response ( 200 , array ( 'cache-control ' => 'max-age= ' . ( YEAR_IN_SECONDS + 1000 ) ) ),
91+ includes_url ( 'css/buttons.min.css ' ) => $ this ->build_response ( 200 , array ( 'etag ' => '"123456789" ' ) ),
92+ includes_url ( 'fonts/dashicons.woff2 ' ) => $ this ->build_response ( 200 , array ( 'last-modified ' => gmdate ( 'D, d M Y H:i:s ' , time () - 1000 ) . ' GMT ' ) ),
93+ includes_url ( 'images/media/video.png ' ) => $ this ->build_response (
6894 200 ,
6995 array (
7096 'etag ' => '"123456789" ' ,
7197 'last-modified ' => gmdate ( 'D, d M Y H:i:s ' , time () - 1000 ) . ' GMT ' ,
7298 )
7399 ),
74- 'conditional_304 ' => $ this ->build_response ( 304 ),
100+ 'conditional_304 ' => $ this ->build_response ( 304 ),
75101 );
76102
77103 $ result = perflab_ffh_assets_test ();
78104 $ this ->assertEquals ( 'recommended ' , $ result ['status ' ] );
79105 $ this ->assertNotEmpty ( $ result ['actions ' ] );
80106 }
81107
108+ /**
109+ * Test that ETag/Last-Modified is used for conditional requests.
110+ *
111+ * @dataProvider data_provider_conditional_headers
112+ * @covers ::perflab_ffh_try_conditional_request
113+ *
114+ * @param string $url The URL to test.
115+ * @param array<string, string> $headers The headers to send.
116+ * @param array<string, mixed>|WP_Error $response The response to return.
117+ * @param bool $expected The expected result.
118+ */
119+ public function test_try_conditional_request_function ( string $ url , array $ headers , $ response , bool $ expected ): void {
120+ $ this ->mocked_responses = array (
121+ $ url => $ response ,
122+ );
123+
124+ $ result = perflab_ffh_try_conditional_request ( $ url , $ headers );
125+
126+ $ this ->assertEquals ( $ expected , $ result );
127+ }
128+
129+ /**
130+ * Data provider for test_try_conditional_request_function.
131+ *
132+ * @return array<array<mixed>> Data provider.
133+ */
134+ public function data_provider_conditional_headers (): array {
135+ return array (
136+ array (
137+ includes_url ( 'js/wp-embed.min.js ' ),
138+ array ( 'If-None-Match ' => '"123456789" ' ),
139+ $ this ->build_response ( 304 ),
140+ true ,
141+ ),
142+ array (
143+ includes_url ( 'css/buttons.min.css ' ),
144+ array ( 'If-Modified-Since ' => gmdate ( 'D, d M Y H:i:s ' , time () - 1000 ) . ' GMT ' ),
145+ $ this ->build_response ( 304 ),
146+ true ,
147+ ),
148+ array (
149+ includes_url ( 'fonts/dashicons.woff2 ' ),
150+ array ( 'If-None-Match ' => '"123456789" ' ),
151+ $ this ->build_response ( 200 ),
152+ false ,
153+ ),
154+ array (
155+ includes_url ( 'images/media/video.png ' ),
156+ array ( 'If-Modified-Since ' => gmdate ( 'D, d M Y H:i:s ' , time () - 1000 ) . ' GMT ' ),
157+ $ this ->build_response ( 200 ),
158+ false ,
159+ ),
160+ array (
161+ includes_url ( 'images/media/video.png ' ),
162+ array (),
163+ new WP_Error ( 'http_request_failed ' , 'HTTP request failed ' ),
164+ false ,
165+ ),
166+ );
167+ }
168+
82169 /**
83170 * Test that different status messages are returned based on the test results.
84171 *
@@ -90,25 +177,40 @@ public function test_status_messages(): void {
90177 $ this ->mocked_responses = array (
91178 includes_url ( 'js/wp-embed.min.js ' ) => $ this ->build_response ( 200 , array ( 'cache-control ' => 'max-age= ' . ( YEAR_IN_SECONDS - 1000 ) ) ),
92179 includes_url ( 'css/buttons.min.css ' ) => $ this ->build_response ( 200 , array ( 'expires ' => gmdate ( 'D, d M Y H:i:s ' , time () + YEAR_IN_SECONDS - 1000 ) . ' GMT ' ) ),
180+ includes_url ( 'images/blank.gif ' ) => $ this ->build_response (
181+ 200 ,
182+ array (
183+ 'cache-control ' => 'max-age= ' . ( YEAR_IN_SECONDS - 1000 ),
184+ 'expires ' => gmdate ( 'D, d M Y H:i:s ' , time () - 1000 ) . ' GMT ' ,
185+ )
186+ ),
187+ 'conditional_304 ' => $ this ->build_response ( 304 ),
93188 includes_url ( 'fonts/dashicons.woff2 ' ) => $ this ->build_response ( 200 , array ( 'etag ' => '"123456789" ' ) ),
94189 includes_url ( 'images/media/video.png ' ) => $ this ->build_response ( 200 , array () ),
95- 'conditional_304 ' => $ this ->build_response ( 304 ),
190+ includes_url ( 'images/media/video.svg ' ) => new WP_Error ( 'http_request_failed ' , 'HTTP request failed ' ),
191+ includes_url ( 'images/media/code.png ' ) => array (),
96192 );
97193
98194 $ result = perflab_ffh_check_assets (
99195 array (
100196 includes_url ( 'js/wp-embed.min.js ' ),
101197 includes_url ( 'css/buttons.min.css ' ),
198+ includes_url ( 'images/blank.gif ' ),
102199 includes_url ( 'fonts/dashicons.woff2 ' ),
103200 includes_url ( 'images/media/video.png ' ),
201+ includes_url ( 'images/media/video.svg ' ),
202+ includes_url ( 'images/media/code.png ' ),
104203 )
105204 );
106205
107206 $ this ->assertEquals ( 'recommended ' , $ result ['final_status ' ] );
108207 $ this ->assertStringContainsString ( 'max-age below threshold (actual: ' , $ result ['details ' ][0 ]['reason ' ] );
109208 $ this ->assertStringContainsString ( 'expires below threshold (actual: ' , $ result ['details ' ][1 ]['reason ' ] );
110- $ this ->assertEquals ( 'No far-future headers but conditionally cached ' , $ result ['details ' ][2 ]['reason ' ] );
111- $ this ->assertEquals ( 'No far-future headers and no conditional caching ' , $ result ['details ' ][3 ]['reason ' ] );
209+ $ this ->assertStringContainsString ( 'max-age below threshold (actual: ' , $ result ['details ' ][2 ]['reason ' ] );
210+ $ this ->assertEquals ( 'No far-future headers but conditionally cached ' , $ result ['details ' ][3 ]['reason ' ] );
211+ $ this ->assertEquals ( 'No far-future headers and no conditional caching ' , $ result ['details ' ][4 ]['reason ' ] );
212+ $ this ->assertEquals ( 'Could not retrieve headers ' , $ result ['details ' ][5 ]['reason ' ] );
213+ $ this ->assertEquals ( 'No valid headers retrieved ' , $ result ['details ' ][6 ]['reason ' ] );
112214 }
113215
114216 /**
@@ -177,9 +279,9 @@ public function test_when_no_assets(): void {
177279 * @param bool $response A preemptive return value of an HTTP request. Default false.
178280 * @param array<string, mixed> $args Request arguments.
179281 * @param string $url The request URL.
180- * @return array<string, mixed> Mocked response.
282+ * @return array<string, mixed>|WP_Error Mocked response.
181283 */
182- public function mock_http_requests ( bool $ response , array $ args , string $ url ): array {
284+ public function mock_http_requests ( bool $ response , array $ args , string $ url ) {
183285 // If conditional headers used in second request, simulate a 304 response.
184286 if ( isset ( $ this ->mocked_responses ['conditional_304 ' ] ) && ( isset ( $ args ['headers ' ]['If-None-Match ' ] ) || isset ( $ args ['headers ' ]['If-Modified-Since ' ] ) ) ) {
185287 return $ this ->mocked_responses ['conditional_304 ' ];
0 commit comments