mirror of
https://github.com/gosticks/wordpress-develop.git
synced 2025-10-16 12:05:38 +00:00
Now that the pattern API request includes the locale and version, the cache key needs to contain a hash of the query args. Props ocean90, dd32, timothyblynjacobs Fixes #53435 git-svn-id: https://develop.svn.wordpress.org/trunk@51208 602fd350-edb4-49c9-b593-d223f7449a82
465 lines
14 KiB
PHP
465 lines
14 KiB
PHP
<?php
|
|
/**
|
|
* Unit tests covering WP_REST_Pattern_Directory_Controller functionality.
|
|
*
|
|
* @package WordPress
|
|
* @subpackage REST API
|
|
*/
|
|
|
|
/**
|
|
* @group restapi
|
|
* @group pattern-directory
|
|
*/
|
|
class WP_REST_Pattern_Directory_Controller_Test extends WP_Test_REST_Controller_Testcase {
|
|
|
|
/**
|
|
* Contributor user id.
|
|
*
|
|
* @since 5.8.0
|
|
*
|
|
* @var int
|
|
*/
|
|
protected static $contributor_id;
|
|
|
|
/**
|
|
* Set up class test fixtures.
|
|
*
|
|
* @since 5.8.0
|
|
*
|
|
* @param WP_UnitTest_Factory $factory WordPress unit test factory.
|
|
*/
|
|
public static function wpSetUpBeforeClass( $factory ) {
|
|
self::$contributor_id = $factory->user->create(
|
|
array(
|
|
'role' => 'contributor',
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Asserts that the pattern matches the expected response schema.
|
|
*
|
|
* @param WP_REST_Response[] $pattern An individual pattern from the REST API response.
|
|
*/
|
|
public function assertPatternMatchesSchema( $pattern ) {
|
|
$schema = ( new WP_REST_Pattern_Directory_Controller() )->get_item_schema();
|
|
$pattern_id = isset( $pattern->id ) ? $pattern->id : '{pattern ID is missing}';
|
|
|
|
$this->assertTrue(
|
|
rest_validate_value_from_schema( $pattern, $schema ),
|
|
"Pattern ID `$pattern_id` doesn't match the response schema."
|
|
);
|
|
|
|
$this->assertSame(
|
|
array_keys( $schema['properties'] ),
|
|
array_keys( $pattern ),
|
|
"Pattern ID `$pattern_id` doesn't contain all of the fields expected from the schema."
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::register_routes
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_register_routes() {
|
|
$routes = rest_get_server()->get_routes();
|
|
|
|
$this->assertArrayHasKey( '/wp/v2/pattern-directory/patterns', $routes );
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_context_param
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_context_param() {
|
|
$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/pattern-directory/patterns' );
|
|
$response = rest_get_server()->dispatch( $request );
|
|
$patterns = $response->get_data();
|
|
|
|
$this->assertSame( 'view', $patterns['endpoints'][0]['args']['context']['default'] );
|
|
$this->assertSame( array( 'view', 'embed' ), $patterns['endpoints'][0]['args']['context']['enum'] );
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_items
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_get_items() {
|
|
wp_set_current_user( self::$contributor_id );
|
|
self::mock_successful_response( 'browse-all', true );
|
|
|
|
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
|
|
$response = rest_do_request( $request );
|
|
$patterns = $response->get_data();
|
|
|
|
$this->assertNotWPError( $response->as_error() );
|
|
$this->assertSame( 200, $response->status );
|
|
$this->assertGreaterThan( 0, count( $patterns ) );
|
|
|
|
array_walk( $patterns, array( $this, 'assertPatternMatchesSchema' ) );
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_items
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_get_items_by_category() {
|
|
wp_set_current_user( self::$contributor_id );
|
|
self::mock_successful_response( 'browse-category', true );
|
|
|
|
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
|
|
$request->set_query_params( array( 'category' => 2 ) );
|
|
$response = rest_do_request( $request );
|
|
$patterns = $response->get_data();
|
|
|
|
$this->assertNotWPError( $response->as_error() );
|
|
$this->assertSame( 200, $response->status );
|
|
$this->assertGreaterThan( 0, count( $patterns ) );
|
|
|
|
array_walk( $patterns, array( $this, 'assertPatternMatchesSchema' ) );
|
|
|
|
foreach ( $patterns as $pattern ) {
|
|
$this->assertContains( 'buttons', $pattern['categories'] );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_items
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_get_items_by_keyword() {
|
|
wp_set_current_user( self::$contributor_id );
|
|
self::mock_successful_response( 'browse-keyword', true );
|
|
|
|
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
|
|
$request->set_query_params( array( 'keyword' => 11 ) );
|
|
$response = rest_do_request( $request );
|
|
$patterns = $response->get_data();
|
|
|
|
$this->assertNotWPError( $response->as_error() );
|
|
$this->assertSame( 200, $response->status );
|
|
$this->assertGreaterThan( 0, count( $patterns ) );
|
|
|
|
array_walk( $patterns, array( $this, 'assertPatternMatchesSchema' ) );
|
|
|
|
foreach ( $patterns as $pattern ) {
|
|
$this->assertContains( 'core', $pattern['keywords'] );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_items
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_get_items_search() {
|
|
wp_set_current_user( self::$contributor_id );
|
|
self::mock_successful_response( 'search', true );
|
|
|
|
$search_term = 'button';
|
|
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
|
|
$request->set_query_params( array( 'search' => $search_term ) );
|
|
$response = rest_do_request( $request );
|
|
$patterns = $response->get_data();
|
|
|
|
$this->assertNotWPError( $response->as_error() );
|
|
$this->assertSame( 200, $response->status );
|
|
$this->assertGreaterThan( 0, count( $patterns ) );
|
|
|
|
array_walk( $patterns, array( $this, 'assertPatternMatchesSchema' ) );
|
|
|
|
foreach ( $patterns as $pattern ) {
|
|
$search_field_values = $pattern['title'] . ' ' . $pattern['description'];
|
|
|
|
$this->assertNotFalse( stripos( $search_field_values, $search_term ) );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_items
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_get_items_wdotorg_unavailable() {
|
|
wp_set_current_user( self::$contributor_id );
|
|
self::prevent_requests_to_host( 'api.wordpress.org' );
|
|
|
|
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
|
|
$response = rest_do_request( $request );
|
|
|
|
$this->assertErrorResponse( 'patterns_api_failed', $response, 500 );
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_items
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_get_items_logged_out() {
|
|
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
|
|
$request->set_query_params( array( 'search' => 'button' ) );
|
|
$response = rest_do_request( $request );
|
|
|
|
$this->assertErrorResponse( 'rest_pattern_directory_cannot_view', $response );
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_items
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_get_items_no_results() {
|
|
wp_set_current_user( self::$contributor_id );
|
|
self::mock_successful_response( 'browse-all', false );
|
|
|
|
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
|
|
$request->set_query_params( array( 'category' => PHP_INT_MAX ) );
|
|
$response = rest_do_request( $request );
|
|
$patterns = $response->get_data();
|
|
|
|
$this->assertSame( 200, $response->status );
|
|
$this->assertSame( array(), $patterns );
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_items
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_get_items_search_no_results() {
|
|
wp_set_current_user( self::$contributor_id );
|
|
self::mock_successful_response( 'search', false );
|
|
|
|
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
|
|
$request->set_query_params( array( 'search' => '0c4549ee68f24eaaed46a49dc983ecde' ) );
|
|
$response = rest_do_request( $request );
|
|
$patterns = $response->get_data();
|
|
|
|
$this->assertSame( 200, $response->status );
|
|
$this->assertSame( array(), $patterns );
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_items
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_get_items_invalid_response_data() {
|
|
wp_set_current_user( self::$contributor_id );
|
|
self::mock_successful_response( 'invalid-data', true );
|
|
|
|
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
|
|
$response = rest_do_request( $request );
|
|
|
|
$this->assertSame( 500, $response->status );
|
|
$this->assertWPError( $response->as_error() );
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_items
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_get_items_prepare_filter() {
|
|
wp_set_current_user( self::$contributor_id );
|
|
self::mock_successful_response( 'browse-all', true );
|
|
|
|
// Test that filter changes uncached values.
|
|
add_filter(
|
|
'rest_prepare_block_pattern',
|
|
function( $response ) {
|
|
return 'initial value';
|
|
}
|
|
);
|
|
|
|
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
|
|
$response = rest_do_request( $request );
|
|
$patterns = $response->get_data();
|
|
|
|
$this->assertSame( 'initial value', $patterns[0] );
|
|
|
|
// Test that filter changes cached values (the previous request primed the cache).
|
|
add_filter(
|
|
'rest_prepare_block_pattern',
|
|
function( $response ) {
|
|
return 'modified the cache';
|
|
},
|
|
11
|
|
);
|
|
|
|
// Test that the filter works against cached values.
|
|
$request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' );
|
|
$response = rest_do_request( $request );
|
|
$patterns = $response->get_data();
|
|
|
|
$this->assertSame( 'modified the cache', $patterns[0] );
|
|
}
|
|
|
|
public function test_get_item() {
|
|
$this->markTestSkipped( 'Controller does not have get_item route.' );
|
|
}
|
|
|
|
public function test_create_item() {
|
|
$this->markTestSkipped( 'Controller does not have create_item route.' );
|
|
}
|
|
|
|
public function test_update_item() {
|
|
$this->markTestSkipped( 'Controller does not have update_item route.' );
|
|
}
|
|
|
|
public function test_delete_item() {
|
|
$this->markTestSkipped( 'Controller does not have delete_item route.' );
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::prepare_item_for_response
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_prepare_item() {
|
|
$controller = new WP_REST_Pattern_Directory_Controller();
|
|
$raw_patterns = json_decode( self::get_raw_response( 'browse-all' ) );
|
|
$raw_patterns[0]->extra_field = 'this should be removed';
|
|
|
|
$prepared_pattern = $controller->prepare_response_for_collection(
|
|
$controller->prepare_item_for_response( $raw_patterns[0], new WP_REST_Request() )
|
|
);
|
|
|
|
$this->assertPatternMatchesSchema( $prepared_pattern );
|
|
$this->assertArrayNotHasKey( 'extra_field', $prepared_pattern );
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::prepare_item_for_response
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_prepare_item_search() {
|
|
$controller = new WP_REST_Pattern_Directory_Controller();
|
|
$raw_patterns = json_decode( self::get_raw_response( 'search' ) );
|
|
$raw_patterns[0]->extra_field = 'this should be removed';
|
|
|
|
$prepared_pattern = $controller->prepare_response_for_collection(
|
|
$controller->prepare_item_for_response( $raw_patterns[0], new WP_REST_Request() )
|
|
);
|
|
|
|
$this->assertPatternMatchesSchema( $prepared_pattern );
|
|
$this->assertArrayNotHasKey( 'extra_field', $prepared_pattern );
|
|
}
|
|
|
|
/**
|
|
* Get a mocked raw response from api.wordpress.org.
|
|
*
|
|
* @return string
|
|
*/
|
|
private static function get_raw_response( $action ) {
|
|
$fixtures_dir = DIR_TESTDATA . '/blocks/pattern-directory';
|
|
|
|
switch ( $action ) {
|
|
default:
|
|
case 'browse-all':
|
|
// Response from https://api.wordpress.org/patterns/1.0/.
|
|
$response = file_get_contents( $fixtures_dir . '/browse-all.json' );
|
|
break;
|
|
|
|
case 'browse-category':
|
|
// Response from https://api.wordpress.org/patterns/1.0/?pattern-categories=2.
|
|
$response = file_get_contents( $fixtures_dir . '/browse-category-2.json' );
|
|
break;
|
|
|
|
case 'browse-keyword':
|
|
// Response from https://api.wordpress.org/patterns/1.0/?pattern-keywords=11.
|
|
$response = file_get_contents( $fixtures_dir . '/browse-keyword-11.json' );
|
|
break;
|
|
|
|
case 'search':
|
|
// Response from https://api.wordpress.org/patterns/1.0/?search=button.
|
|
$response = file_get_contents( $fixtures_dir . '/search-button.json' );
|
|
break;
|
|
|
|
case 'invalid-data':
|
|
$response = ''; // Any HTTP 200 response from w.org should be in JSON, even if it contains an error message.
|
|
break;
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* @covers WP_REST_Pattern_Directory_Controller::get_item_schema
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
public function test_get_item_schema() {
|
|
$this->markTestSkipped( "The controller's schema is hardcoded, so tests would not be meaningful." );
|
|
}
|
|
|
|
/**
|
|
* Simulate a successful outbound HTTP requests, to keep tests pure and performant.
|
|
*
|
|
* @param string $action Pass a case from `get_raw_response()` to determine returned data.
|
|
* @param bool $expects_results Pass `true` to get results, or `false` to get 0 results.
|
|
*
|
|
* @since 5.8.0
|
|
*/
|
|
private static function mock_successful_response( $action, $expects_results ) {
|
|
add_filter(
|
|
'pre_http_request',
|
|
static function ( $preempt, $args, $url ) use ( $action, $expects_results ) {
|
|
|
|
if ( 'api.wordpress.org' !== wp_parse_url( $url, PHP_URL_HOST ) ) {
|
|
return $preempt;
|
|
}
|
|
|
|
$response = array(
|
|
'headers' => array(),
|
|
'response' => array(
|
|
'code' => 200,
|
|
'message' => 'OK',
|
|
),
|
|
'body' => $expects_results ? self::get_raw_response( $action ) : '[]',
|
|
'cookies' => array(),
|
|
'filename' => null,
|
|
);
|
|
|
|
return $response;
|
|
},
|
|
10,
|
|
3
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Simulate a network failure on outbound http requests to a given hostname.
|
|
*
|
|
* @since 5.8.0
|
|
*
|
|
* @param string $blocked_host The host to block connections to.
|
|
*/
|
|
private static function prevent_requests_to_host( $blocked_host = 'api.wordpress.org' ) {
|
|
add_filter(
|
|
'pre_http_request',
|
|
static function ( $return, $args, $url ) use ( $blocked_host ) {
|
|
|
|
if ( wp_parse_url( $url, PHP_URL_HOST ) === $blocked_host ) {
|
|
return new WP_Error(
|
|
'patterns_api_failed',
|
|
"An expected error occurred connecting to $blocked_host because of a unit test.",
|
|
"cURL error 7: Failed to connect to $blocked_host port 80: Connection refused"
|
|
);
|
|
|
|
}
|
|
|
|
return $return;
|
|
},
|
|
10,
|
|
3
|
|
);
|
|
}
|
|
}
|