block-type.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. <?php
  2. /**
  3. * WP_Block_Type Tests
  4. *
  5. * @package WordPress
  6. * @subpackage Blocks
  7. * @since 5.0.0
  8. */
  9. /**
  10. * Tests for WP_Block_Type
  11. *
  12. * @since 5.0.0
  13. *
  14. * @group blocks
  15. */
  16. class WP_Test_Block_Type extends WP_UnitTestCase {
  17. /**
  18. * Editor user ID.
  19. *
  20. * @since 5.0.0
  21. * @var int
  22. */
  23. protected static $editor_user_id;
  24. /**
  25. * ID for a post containing blocks.
  26. *
  27. * @since 5.0.0
  28. * @var int
  29. */
  30. protected static $post_with_blocks;
  31. /**
  32. * ID for a post without blocks.
  33. *
  34. * @since 5.0.0
  35. * @var int
  36. */
  37. protected static $post_without_blocks;
  38. /**
  39. * Set up before class.
  40. *
  41. * @since 5.0.0
  42. */
  43. public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
  44. self::$editor_user_id = $factory->user->create(
  45. array(
  46. 'role' => 'editor',
  47. )
  48. );
  49. self::$post_with_blocks = $factory->post->create(
  50. array(
  51. 'post_title' => 'Example',
  52. 'post_content' => "<!-- wp:core/text {\"dropCap\":true} -->\n<p class=\"has-drop-cap\">Tester</p>\n<!-- /wp:core/text -->",
  53. )
  54. );
  55. self::$post_without_blocks = $factory->post->create(
  56. array(
  57. 'post_title' => 'Example',
  58. 'post_content' => 'Tester',
  59. )
  60. );
  61. }
  62. /**
  63. * @ticket 45097
  64. */
  65. public function test_set_props() {
  66. $name = 'core/fake';
  67. $args = array(
  68. 'render_callback' => array( $this, 'render_fake_block' ),
  69. 'foo' => 'bar',
  70. );
  71. $block_type = new WP_Block_Type( $name, $args );
  72. $this->assertSame( $name, $block_type->name );
  73. $this->assertSame( $args['render_callback'], $block_type->render_callback );
  74. $this->assertSame( $args['foo'], $block_type->foo );
  75. }
  76. /**
  77. * @ticket 45097
  78. */
  79. public function test_render() {
  80. $attributes = array(
  81. 'foo' => 'bar',
  82. 'bar' => 'foo',
  83. );
  84. $block_type = new WP_Block_Type(
  85. 'core/fake',
  86. array(
  87. 'render_callback' => array( $this, 'render_fake_block' ),
  88. )
  89. );
  90. $output = $block_type->render( $attributes );
  91. $this->assertSame( $attributes, json_decode( $output, true ) );
  92. }
  93. /**
  94. * @ticket 45097
  95. */
  96. public function test_render_with_content() {
  97. $attributes = array(
  98. 'foo' => 'bar',
  99. 'bar' => 'foo',
  100. );
  101. $content = 'baz';
  102. $expected = array_merge( $attributes, array( '_content' => $content ) );
  103. $block_type = new WP_Block_Type(
  104. 'core/fake',
  105. array(
  106. 'render_callback' => array( $this, 'render_fake_block_with_content' ),
  107. )
  108. );
  109. $output = $block_type->render( $attributes, $content );
  110. $this->assertSame( $expected, json_decode( $output, true ) );
  111. }
  112. /**
  113. * @ticket 45097
  114. */
  115. public function test_render_for_static_block() {
  116. $block_type = new WP_Block_Type( 'core/fake', array() );
  117. $output = $block_type->render();
  118. $this->assertSame( '', $output );
  119. }
  120. /**
  121. * @ticket 45097
  122. */
  123. public function test_is_dynamic_for_static_block() {
  124. $block_type = new WP_Block_Type( 'core/fake', array() );
  125. $this->assertFalse( $block_type->is_dynamic() );
  126. }
  127. /**
  128. * @ticket 45097
  129. */
  130. public function test_is_dynamic_for_dynamic_block() {
  131. $block_type = new WP_Block_Type(
  132. 'core/fake',
  133. array(
  134. 'render_callback' => array( $this, 'render_fake_block' ),
  135. )
  136. );
  137. $this->assertTrue( $block_type->is_dynamic() );
  138. }
  139. /**
  140. * @ticket 45097
  141. */
  142. public function test_prepare_attributes() {
  143. $attributes = array(
  144. 'correct' => 'include',
  145. 'wrongType' => 5,
  146. 'wrongTypeDefaulted' => 5,
  147. /* missingDefaulted */
  148. 'undefined' => 'include',
  149. 'intendedNull' => null,
  150. );
  151. $block_type = new WP_Block_Type(
  152. 'core/fake',
  153. array(
  154. 'attributes' => array(
  155. 'correct' => array(
  156. 'type' => 'string',
  157. ),
  158. 'wrongType' => array(
  159. 'type' => 'string',
  160. ),
  161. 'wrongTypeDefaulted' => array(
  162. 'type' => 'string',
  163. 'default' => 'defaulted',
  164. ),
  165. 'missingDefaulted' => array(
  166. 'type' => 'string',
  167. 'default' => 'define',
  168. ),
  169. 'intendedNull' => array(
  170. 'type' => array( 'string', 'null' ),
  171. 'default' => 'wrong',
  172. ),
  173. ),
  174. )
  175. );
  176. $prepared_attributes = $block_type->prepare_attributes_for_render( $attributes );
  177. $this->assertEquals(
  178. array(
  179. 'correct' => 'include',
  180. /* wrongType */
  181. 'wrongTypeDefaulted' => 'defaulted',
  182. 'missingDefaulted' => 'define',
  183. 'undefined' => 'include',
  184. 'intendedNull' => null,
  185. ),
  186. $prepared_attributes
  187. );
  188. }
  189. /**
  190. * @ticket 45145
  191. */
  192. function test_prepare_attributes_none_defined() {
  193. $attributes = array( 'exists' => 'keep' );
  194. $block_type = new WP_Block_Type( 'core/dummy', array() );
  195. $prepared_attributes = $block_type->prepare_attributes_for_render( $attributes );
  196. $this->assertSame( $attributes, $prepared_attributes );
  197. }
  198. /**
  199. * @ticket 45097
  200. */
  201. public function test_has_block_with_mixed_content() {
  202. $mixed_post_content = 'before' .
  203. '<!-- wp:core/fake --><!-- /wp:core/fake -->' .
  204. '<!-- wp:core/fake_atts {"value":"b1"} --><!-- /wp:core/fake_atts -->' .
  205. '<!-- wp:core/fake-child -->
  206. <p>testing the test</p>
  207. <!-- /wp:core/fake-child -->' .
  208. 'between' .
  209. '<!-- wp:core/self-close-fake /-->' .
  210. '<!-- wp:custom/fake {"value":"b2"} /-->' .
  211. 'after';
  212. $this->assertTrue( has_block( 'core/fake', $mixed_post_content ) );
  213. $this->assertTrue( has_block( 'core/fake_atts', $mixed_post_content ) );
  214. $this->assertTrue( has_block( 'core/fake-child', $mixed_post_content ) );
  215. $this->assertTrue( has_block( 'core/self-close-fake', $mixed_post_content ) );
  216. $this->assertTrue( has_block( 'custom/fake', $mixed_post_content ) );
  217. // checking for a partial block name should fail.
  218. $this->assertFalse( has_block( 'core/fak', $mixed_post_content ) );
  219. // checking for a wrong namespace should fail.
  220. $this->assertFalse( has_block( 'custom/fake_atts', $mixed_post_content ) );
  221. // checking for namespace only should not work. Or maybe ... ?
  222. $this->assertFalse( has_block( 'core', $mixed_post_content ) );
  223. }
  224. /**
  225. * @ticket 45097
  226. */
  227. public function test_has_block_with_invalid_content() {
  228. // some content with invalid HMTL comments and a single valid block.
  229. $invalid_content = 'before' .
  230. '<!- - wp:core/weird-space --><!-- /wp:core/weird-space -->' .
  231. '<!--wp:core/untrimmed-left --><!-- /wp:core/untrimmed -->' .
  232. '<!-- wp:core/fake --><!-- /wp:core/fake -->' .
  233. '<!-- wp:core/untrimmed-right--><!-- /wp:core/untrimmed2 -->' .
  234. 'after';
  235. $this->assertFalse( has_block( 'core/text', self::$post_without_blocks ) );
  236. $this->assertFalse( has_block( 'core/weird-space', $invalid_content ) );
  237. $this->assertFalse( has_block( 'core/untrimmed-left', $invalid_content ) );
  238. $this->assertFalse( has_block( 'core/untrimmed-right', $invalid_content ) );
  239. $this->assertTrue( has_block( 'core/fake', $invalid_content ) );
  240. }
  241. /**
  242. * @ticket 45097
  243. */
  244. public function test_post_has_block() {
  245. // should fail for a non-existent block `custom/fake`.
  246. $this->assertFalse( has_block( 'custom/fake', self::$post_with_blocks ) );
  247. // this functions should not work without the second param until the $post global is set.
  248. $this->assertFalse( has_block( 'core/text' ) );
  249. $this->assertFalse( has_block( 'core/fake' ) );
  250. global $post;
  251. $post = get_post( self::$post_with_blocks );
  252. // check if the function correctly detects content from the $post global.
  253. $this->assertTrue( has_block( 'core/text' ) );
  254. // even if it detects a proper $post global it should still be false for a missing block.
  255. $this->assertFalse( has_block( 'core/fake' ) );
  256. }
  257. public function test_post_has_block_serialized_name() {
  258. $content = '<!-- wp:serialized /--><!-- wp:core/normalized /--><!-- wp:plugin/third-party /-->';
  259. $this->assertTrue( has_block( 'core/serialized', $content ) );
  260. /*
  261. * Technically, `has_block` should receive a "full" (normalized, parsed)
  262. * block name. But this test conforms to expected pre-5.3.1 behavior.
  263. */
  264. $this->assertTrue( has_block( 'serialized', $content ) );
  265. $this->assertTrue( has_block( 'core/normalized', $content ) );
  266. $this->assertTrue( has_block( 'normalized', $content ) );
  267. $this->assertFalse( has_block( 'plugin/normalized', $content ) );
  268. $this->assertFalse( has_block( 'plugin/serialized', $content ) );
  269. $this->assertFalse( has_block( 'third-party', $content ) );
  270. $this->assertFalse( has_block( 'core/third-party', $content ) );
  271. }
  272. /**
  273. * Renders a test block without content.
  274. *
  275. * @since 5.0.0
  276. *
  277. * @param array $attributes Block attributes. Default empty array.
  278. * @return string JSON encoded list of attributes.
  279. */
  280. public function render_fake_block( $attributes ) {
  281. return json_encode( $attributes );
  282. }
  283. /**
  284. * Renders a test block with content.
  285. *
  286. * @since 5.0.0
  287. *
  288. * @param array $attributes Block attributes. Default empty array.
  289. * @param string $content Block content. Default empty string.
  290. * @return string JSON encoded list of attributes.
  291. */
  292. public function render_fake_block_with_content( $attributes, $content ) {
  293. $attributes['_content'] = $content;
  294. return json_encode( $attributes );
  295. }
  296. /**
  297. * @ticket 48529
  298. */
  299. public function test_register_block() {
  300. $block_type = new WP_Block_Type(
  301. 'core/fake',
  302. array(
  303. 'title' => 'Test title',
  304. 'category' => 'Test category',
  305. 'parent' => array( 'core/third-party' ),
  306. 'icon' => 'icon.png',
  307. 'description' => 'test description',
  308. 'keywords' => array( 'test keyword' ),
  309. 'textdomain' => 'test_domain',
  310. 'supports' => array( 'alignment' => true ),
  311. )
  312. );
  313. $this->assertSame( 'Test title', $block_type->title );
  314. $this->assertSame( 'Test category', $block_type->category );
  315. $this->assertSameSets( array( 'core/third-party' ), $block_type->parent );
  316. $this->assertSame( 'icon.png', $block_type->icon );
  317. $this->assertSame( 'test description', $block_type->description );
  318. $this->assertSameSets( array( 'test keyword' ), $block_type->keywords );
  319. $this->assertSame( 'test_domain', $block_type->textdomain );
  320. $this->assertSameSets( array( 'alignment' => true ), $block_type->supports );
  321. }
  322. /**
  323. * Testing the block version.
  324. *
  325. * @ticket 43887
  326. *
  327. * @dataProvider data_block_version
  328. *
  329. * @param string|null $content Content.
  330. * @param int $expected Expected block version.
  331. */
  332. public function test_block_version( $content, $expected ) {
  333. $this->assertSame( $expected, block_version( $content ) );
  334. }
  335. /**
  336. * Test cases for test_block_version().
  337. *
  338. * @since 5.0.0
  339. *
  340. * @return array {
  341. * @type array {
  342. * @type string|null Content.
  343. * @type int Expected block version.
  344. * }
  345. * }
  346. */
  347. public function data_block_version() {
  348. return array(
  349. // Null.
  350. array( null, 0 ),
  351. // Empty post content.
  352. array( '', 0 ),
  353. // Post content without blocks.
  354. array( '<hr class="wp-block-separator" />', 0 ),
  355. // Post content with a block.
  356. array( '<!-- wp:core/separator -->', 1 ),
  357. // Post content with a fake block.
  358. array( '<!-- wp:core/fake --><!-- /wp:core/fake -->', 1 ),
  359. // Post content with an invalid block.
  360. array( '<!- - wp:core/separator -->', 0 ),
  361. );
  362. }
  363. }