rest-block-directory-controller.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. <?php
  2. /**
  3. * Unit tests covering WP_REST_Block_Directory_Controller functionality.
  4. *
  5. * @package WordPress
  6. * @subpackage REST API
  7. */
  8. /**
  9. * @group restapi
  10. */
  11. class WP_REST_Block_Directory_Controller_Test extends WP_Test_REST_Controller_Testcase {
  12. /**
  13. * Administrator user id.
  14. *
  15. * @since 5.5.0
  16. *
  17. * @var int
  18. */
  19. protected static $admin_id;
  20. /**
  21. * Set up class test fixtures.
  22. *
  23. * @since 5.5.0
  24. *
  25. * @param WP_UnitTest_Factory $factory WordPress unit test factory.
  26. */
  27. public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
  28. self::$admin_id = $factory->user->create(
  29. array(
  30. 'role' => 'administrator',
  31. )
  32. );
  33. if ( is_multisite() ) {
  34. grant_super_admin( self::$admin_id );
  35. }
  36. }
  37. public static function wpTearDownAfterClass() {
  38. self::delete_user( self::$admin_id );
  39. }
  40. /**
  41. * @ticket 50321
  42. */
  43. public function test_register_routes() {
  44. $routes = rest_get_server()->get_routes();
  45. $this->assertArrayHasKey( '/wp/v2/block-directory/search', $routes );
  46. }
  47. /**
  48. * @ticket 50321
  49. */
  50. public function test_context_param() {
  51. // Collection.
  52. $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/block-directory/search' );
  53. $response = rest_get_server()->dispatch( $request );
  54. $data = $response->get_data();
  55. $this->assertSame( 'view', $data['endpoints'][0]['args']['context']['default'] );
  56. $this->assertSame( array( 'view' ), $data['endpoints'][0]['args']['context']['enum'] );
  57. }
  58. /**
  59. * @ticket 50321
  60. */
  61. public function test_get_items() {
  62. wp_set_current_user( self::$admin_id );
  63. $request = new WP_REST_Request( 'GET', '/wp/v2/block-directory/search' );
  64. $request->set_query_params( array( 'term' => 'foo' ) );
  65. $result = rest_do_request( $request );
  66. $this->assertNotWPError( $result->as_error() );
  67. $this->assertSame( 200, $result->status );
  68. }
  69. /**
  70. * @ticket 50321
  71. */
  72. public function test_get_items_wdotorg_unavailable() {
  73. wp_set_current_user( self::$admin_id );
  74. $request = new WP_REST_Request( 'GET', '/wp/v2/block-directory/search' );
  75. $request->set_query_params( array( 'term' => 'foo' ) );
  76. $this->prevent_requests_to_host( 'api.wordpress.org' );
  77. $this->expectException( 'PHPUnit_Framework_Error_Warning' );
  78. $response = rest_do_request( $request );
  79. $this->assertErrorResponse( 'plugins_api_failed', $response, 500 );
  80. }
  81. /**
  82. * @ticket 50321
  83. */
  84. public function test_get_items_logged_out() {
  85. $request = new WP_REST_Request( 'GET', '/wp/v2/block-directory/search' );
  86. $request->set_query_params( array( 'term' => 'foo' ) );
  87. $response = rest_do_request( $request );
  88. $this->assertErrorResponse( 'rest_block_directory_cannot_view', $response );
  89. }
  90. /**
  91. * @ticket 50321
  92. */
  93. public function test_get_items_no_results() {
  94. wp_set_current_user( self::$admin_id );
  95. $request = new WP_REST_Request( 'GET', '/wp/v2/block-directory/search' );
  96. $request->set_query_params( array( 'term' => '0c4549ee68f24eaaed46a49dc983ecde' ) );
  97. $response = rest_do_request( $request );
  98. $data = $response->get_data();
  99. // Should produce a 200 status with an empty array.
  100. $this->assertSame( 200, $response->status );
  101. $this->assertSame( array(), $data );
  102. }
  103. public function test_get_item() {
  104. $this->markTestSkipped( 'Controller does not have get_item route.' );
  105. }
  106. public function test_create_item() {
  107. $this->markTestSkipped( 'Controller does not have create_item route.' );
  108. }
  109. public function test_update_item() {
  110. $this->markTestSkipped( 'Controller does not have update_item route.' );
  111. }
  112. public function test_delete_item() {
  113. $this->markTestSkipped( 'Controller does not have delete_item route.' );
  114. }
  115. /**
  116. * @ticket 50321
  117. */
  118. public function test_prepare_item() {
  119. wp_set_current_user( self::$admin_id );
  120. $controller = new WP_REST_Block_Directory_Controller();
  121. $plugin = $this->get_mock_plugin();
  122. $request = new WP_REST_Request( 'GET', '/wp/v2/block-directory/search' );
  123. $request->set_query_params( array( 'term' => 'block' ) );
  124. $response = $controller->prepare_item_for_response( $plugin, $request );
  125. $expected = array(
  126. 'name' => 'sortabrilliant/guidepost',
  127. 'title' => 'Guidepost',
  128. 'description' => 'A guidepost gives you directions. It lets you know where you’re going. It gives you a preview of what’s to come.',
  129. 'id' => 'guidepost',
  130. 'rating' => 4.3,
  131. 'rating_count' => 90,
  132. 'active_installs' => 100,
  133. 'author_block_rating' => 0,
  134. 'author_block_count' => 1,
  135. 'author' => 'sorta brilliant',
  136. 'icon' => 'https://ps.w.org/guidepost/assets/icon-128x128.jpg?rev=2235512',
  137. 'last_updated' => gmdate( 'Y-m-d\TH:i:s', strtotime( $plugin['last_updated'] ) ),
  138. 'humanized_updated' => sprintf( '%s ago', human_time_diff( strtotime( $plugin['last_updated'] ) ) ),
  139. );
  140. $this->assertSame( $expected, $response->get_data() );
  141. }
  142. /**
  143. * @ticket 50321
  144. */
  145. public function test_get_item_schema() {
  146. wp_set_current_user( self::$admin_id );
  147. $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/block-directory/search' );
  148. $request->set_query_params( array( 'term' => 'foo' ) );
  149. $response = rest_do_request( $request );
  150. $data = $response->get_data();
  151. // Check endpoints
  152. $this->assertSame( array( 'GET' ), $data['endpoints'][0]['methods'] );
  153. $this->assertTrue( $data['endpoints'][0]['args']['term']['required'] );
  154. $properties = $data['schema']['properties'];
  155. $this->assertCount( 13, $properties );
  156. $this->assertArrayHasKey( 'name', $properties );
  157. $this->assertArrayHasKey( 'title', $properties );
  158. $this->assertArrayHasKey( 'description', $properties );
  159. $this->assertArrayHasKey( 'id', $properties );
  160. $this->assertArrayHasKey( 'rating', $properties );
  161. $this->assertArrayHasKey( 'rating_count', $properties );
  162. $this->assertArrayHasKey( 'active_installs', $properties );
  163. $this->assertArrayHasKey( 'author_block_rating', $properties );
  164. $this->assertArrayHasKey( 'author_block_count', $properties );
  165. $this->assertArrayHasKey( 'author', $properties );
  166. $this->assertArrayHasKey( 'icon', $properties );
  167. $this->assertArrayHasKey( 'last_updated', $properties );
  168. $this->assertArrayHasKey( 'humanized_updated', $properties );
  169. }
  170. /**
  171. * Simulate a network failure on outbound http requests to a given hostname.
  172. *
  173. * @since 5.5.0
  174. *
  175. * @param string $blocked_host The host to block connections to.
  176. */
  177. private function prevent_requests_to_host( $blocked_host = 'api.wordpress.org' ) {
  178. add_filter(
  179. 'pre_http_request',
  180. static function ( $return, $args, $url ) use ( $blocked_host ) {
  181. if ( @parse_url( $url, PHP_URL_HOST ) === $blocked_host ) {
  182. return new WP_Error( 'plugins_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" );
  183. }
  184. return $return;
  185. },
  186. 10,
  187. 3
  188. );
  189. }
  190. /**
  191. * Gets an example of the data returned from the {@see plugins_api()} for a block.
  192. *
  193. * @since 5.5.0
  194. *
  195. * @return array
  196. */
  197. private function get_mock_plugin() {
  198. return array(
  199. 'name' => 'Guidepost',
  200. 'slug' => 'guidepost',
  201. 'version' => '1.2.1',
  202. 'author' => '<a href="https://sortabrilliant.com">sorta brilliant</a>',
  203. 'author_profile' => 'https://profiles.wordpress.org/sortabrilliant',
  204. 'requires' => '5.0',
  205. 'tested' => '5.4.0',
  206. 'requires_php' => '5.6',
  207. 'rating' => 86,
  208. 'ratings' => array(
  209. 5 => 50,
  210. 4 => 25,
  211. 3 => 7,
  212. 2 => 5,
  213. 1 => 3,
  214. ),
  215. 'num_ratings' => 90,
  216. 'support_threads' => 1,
  217. 'support_threads_resolved' => 0,
  218. 'active_installs' => 100,
  219. 'downloaded' => 1112,
  220. 'last_updated' => '2020-03-23 5:13am GMT',
  221. 'added' => '2020-01-29',
  222. 'homepage' => 'https://sortabrilliant.com/guidepost/',
  223. 'description' => '<p>A guidepost gives you directions. It lets you know where you’re going. It gives you a preview of what’s to come. How does it work? Guideposts are magic, no they really are.</p>',
  224. 'short_description' => 'A guidepost gives you directions. It lets you know where you’re going. It gives you a preview of what’s to come.',
  225. 'download_link' => 'https://downloads.wordpress.org/plugin/guidepost.1.2.1.zip',
  226. 'tags' => array(
  227. 'block' => 'block',
  228. 'heading' => 'heading',
  229. 'style' => 'style',
  230. ),
  231. 'donate_link' => '',
  232. 'icons' => array(
  233. '1x' => 'https://ps.w.org/guidepost/assets/icon-128x128.jpg?rev=2235512',
  234. '2x' => 'https://ps.w.org/guidepost/assets/icon-256x256.jpg?rev=2235512',
  235. ),
  236. 'blocks' => array(
  237. 'sortabrilliant/guidepost' => array(
  238. 'name' => 'sortabrilliant/guidepost',
  239. 'title' => 'Guidepost',
  240. ),
  241. ),
  242. 'block_assets' => array(
  243. 0 => '/tags/1.2.1/build/index.js',
  244. 1 => '/tags/1.2.1/build/guidepost-editor.css',
  245. 2 => '/tags/1.2.1/build/guidepost-style.css',
  246. 3 => '/tags/1.2.1/build/guidepost-theme.js',
  247. ),
  248. 'author_block_count' => 1,
  249. 'author_block_rating' => 0,
  250. );
  251. }
  252. }