core/image
InnerBlocks
component. See the templates documentation for more information. See templates documentation for more information.Hello!
', - ) - ); - - self::$user_ids = array( - 'editor' => $factory->user->create( array( 'role' => 'editor' ) ), - 'author' => $factory->user->create( array( 'role' => 'author' ) ), - 'contributor' => $factory->user->create( array( 'role' => 'contributor' ) ), - ); - } - - /** - * Delete our fake data after our tests run. - */ - public static function wpTearDownAfterClass() { - wp_delete_post( self::$post_id ); - - foreach ( self::$user_ids as $user_id ) { - self::delete_user( $user_id ); - } - } - - /** - * Test cases for test_capabilities(). - */ - public function data_capabilities() { - return array( - array( 'create', 'editor', 201 ), - array( 'create', 'author', 201 ), - array( 'create', 'contributor', 403 ), - array( 'create', null, 401 ), - - array( 'read', 'editor', 200 ), - array( 'read', 'author', 200 ), - array( 'read', 'contributor', 200 ), - array( 'read', null, 401 ), - - array( 'update_delete_own', 'editor', 200 ), - array( 'update_delete_own', 'author', 200 ), - array( 'update_delete_own', 'contributor', 403 ), - - array( 'update_delete_others', 'editor', 200 ), - array( 'update_delete_others', 'author', 403 ), - array( 'update_delete_others', 'contributor', 403 ), - array( 'update_delete_others', null, 401 ), - ); - } - - /** - * Exhaustively check that each role either can or cannot create, edit, - * update, and delete reusable blocks. - * - * @dataProvider data_capabilities - */ - public function test_capabilities( $action, $role, $expected_status ) { - if ( $role ) { - $user_id = self::$user_ids[ $role ]; - wp_set_current_user( $user_id ); - } else { - wp_set_current_user( 0 ); - } - - switch ( $action ) { - case 'create': - $request = new WP_REST_Request( 'POST', '/wp/v2/blocks' ); - $request->set_body_params( - array( - 'title' => 'Test', - 'content' => 'Test
', - ) - ); - - $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( $expected_status, $response->get_status() ); - - break; - - case 'read': - $request = new WP_REST_Request( 'GET', '/wp/v2/blocks/' . self::$post_id ); - - $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( $expected_status, $response->get_status() ); - - break; - - case 'update_delete_own': - $post_id = wp_insert_post( - array( - 'post_type' => 'wp_block', - 'post_status' => 'publish', - 'post_title' => 'My cool block', - 'post_content' => 'Hello!
', - 'post_author' => $user_id, - ) - ); - - $request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . $post_id ); - $request->set_body_params( - array( - 'title' => 'Test', - 'content' => 'Test
', - ) - ); - - $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( $expected_status, $response->get_status() ); - - $request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . $post_id ); - - $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( $expected_status, $response->get_status() ); - - wp_delete_post( $post_id ); - - break; - - case 'update_delete_others': - $request = new WP_REST_Request( 'PUT', '/wp/v2/blocks/' . self::$post_id ); - $request->set_body_params( - array( - 'title' => 'Test', - 'content' => 'Test
', - ) - ); - - $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( $expected_status, $response->get_status() ); - - $request = new WP_REST_Request( 'DELETE', '/wp/v2/blocks/' . self::$post_id ); - - $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( $expected_status, $response->get_status() ); - - break; - - default: - $this->fail( "'$action' is not a valid action." ); - } - } - - /** - * Check that the raw title and content of a block can be accessed when there - * is no set schema, and that the rendered content of a block is not included - * in the response. - */ - public function test_content() { - wp_set_current_user( self::$user_ids['author'] ); - - $request = new WP_REST_Request( 'GET', '/wp/v2/blocks/' . self::$post_id ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertEquals( - array( - 'raw' => 'My cool block', - ), - $data['title'] - ); - $this->assertEquals( - array( - 'raw' => 'Hello!
', - 'protected' => false, - ), - $data['content'] - ); - } -} diff --git a/phpunit/class-rest-search-controller-test.php b/phpunit/class-rest-search-controller-test.php deleted file mode 100644 index 26649037e8ff22..00000000000000 --- a/phpunit/class-rest-search-controller-test.php +++ /dev/null @@ -1,521 +0,0 @@ -post->create_many( - 4, - array( - 'post_title' => 'my-footitle', - 'post_type' => 'post', - ) - ); - - self::$my_title_page_ids = $factory->post->create_many( - 4, - array( - 'post_title' => 'my-footitle', - 'post_type' => 'page', - ) - ); - - self::$my_content_post_ids = $factory->post->create_many( - 6, - array( - 'post_content' => 'my-foocontent', - ) - ); - } - - /** - * Delete our fake data after our tests run. - */ - public static function wpTearDownAfterClass() { - $post_ids = array_merge( - self::$my_title_post_ids, - self::$my_title_page_ids, - self::$my_content_post_ids - ); - - foreach ( $post_ids as $post_id ) { - wp_delete_post( $post_id, true ); - } - } - - /** - * Check that our routes get set up properly. - */ - public function test_register_routes() { - $routes = rest_get_server()->get_routes(); - - $this->assertArrayHasKey( '/wp/v2/search', $routes ); - $this->assertCount( 1, $routes['/wp/v2/search'] ); - } - - /** - * Check the context parameter. - */ - public function test_context_param() { - $response = $this->do_request_with_params( array(), 'OPTIONS' ); - $data = $response->get_data(); - - $this->assertEquals( 'view', $data['endpoints'][0]['args']['context']['default'] ); - $this->assertEquals( array( 'view', 'embed' ), $data['endpoints'][0]['args']['context']['enum'] ); - } - - /** - * Search through all content. - */ - public function test_get_items() { - $response = $this->do_request_with_params( - array( - 'per_page' => 100, - ) - ); - - $this->assertEquals( 200, $response->get_status() ); - $this->assertEqualSets( - array_merge( - self::$my_title_post_ids, - self::$my_title_page_ids, - self::$my_content_post_ids - ), - wp_list_pluck( $response->get_data(), 'id' ) - ); - } - - /** - * Search through all content with a low limit. - */ - public function test_get_items_with_limit() { - $response = $this->do_request_with_params( - array( - 'per_page' => 3, - ) - ); - - $this->assertEquals( 200, $response->get_status() ); - $this->assertEquals( 3, count( $response->get_data() ) ); - } - - /** - * Search through posts of any post type. - */ - public function test_get_items_search_type_post() { - $response = $this->do_request_with_params( - array( - 'per_page' => 100, - 'type' => 'post', - ) - ); - - $this->assertEquals( 200, $response->get_status() ); - $this->assertEqualSets( - array_merge( - self::$my_title_post_ids, - self::$my_title_page_ids, - self::$my_content_post_ids - ), - wp_list_pluck( $response->get_data(), 'id' ) - ); - } - - /** - * Search through posts of post type 'post'. - */ - public function test_get_items_search_type_post_subtype_post() { - $response = $this->do_request_with_params( - array( - 'per_page' => 100, - 'type' => 'post', - 'subtype' => 'post', - ) - ); - - $this->assertEquals( 200, $response->get_status() ); - $this->assertEqualSets( - array_merge( - self::$my_title_post_ids, - self::$my_content_post_ids - ), - wp_list_pluck( $response->get_data(), 'id' ) - ); - } - - /** - * Search through posts of post type 'page'. - */ - public function test_get_items_search_type_post_subtype_page() { - $response = $this->do_request_with_params( - array( - 'per_page' => 100, - 'type' => 'post', - 'subtype' => 'page', - ) - ); - - $this->assertEquals( 200, $response->get_status() ); - $this->assertEqualSets( - self::$my_title_page_ids, - wp_list_pluck( $response->get_data(), 'id' ) - ); - } - - /** - * Search through an invalid type - */ - public function test_get_items_search_type_invalid() { - $response = $this->do_request_with_params( - array( - 'per_page' => 100, - 'type' => 'invalid', - ) - ); - - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - } - - /** - * Search through posts of an invalid post type. - */ - public function test_get_items_search_type_post_subtype_invalid() { - $response = $this->do_request_with_params( - array( - 'per_page' => 100, - 'type' => 'post', - 'subtype' => 'invalid', - ) - ); - - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - } - - /** - * Search through posts and pages. - */ - public function test_get_items_search_posts_and_pages() { - $response = $this->do_request_with_params( - array( - 'per_page' => 100, - 'type' => 'post', - 'subtype' => 'post,page', - ) - ); - - $this->assertEquals( 200, $response->get_status() ); - $this->assertEqualSets( - array_merge( - self::$my_title_post_ids, - self::$my_title_page_ids, - self::$my_content_post_ids - ), - wp_list_pluck( $response->get_data(), 'id' ) - ); - } - - /** - * Search through all that matches a 'footitle' search. - */ - public function test_get_items_search_for_footitle() { - $response = $this->do_request_with_params( - array( - 'per_page' => 100, - 'search' => 'footitle', - ) - ); - - $this->assertEquals( 200, $response->get_status() ); - $this->assertEqualSets( - array_merge( - self::$my_title_post_ids, - self::$my_title_page_ids - ), - wp_list_pluck( $response->get_data(), 'id' ) - ); - } - - /** - * Search through all that matches a 'foocontent' search. - */ - public function test_get_items_search_for_foocontent() { - $response = $this->do_request_with_params( - array( - 'per_page' => 100, - 'search' => 'foocontent', - ) - ); - - $this->assertEquals( 200, $response->get_status() ); - $this->assertEqualSets( - self::$my_content_post_ids, - wp_list_pluck( $response->get_data(), 'id' ) - ); - } - - /** - * Test retrieving a single item isn't possible. - */ - public function test_get_item() { - /** The search controller does not allow getting individual item content */ - $request = new WP_REST_Request( 'GET', '/wp/v2/search' . self::$my_title_post_ids[0] ); - $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( 404, $response->get_status() ); - } - - /** - * Test creating an item isn't possible. - */ - public function test_create_item() { - /** The search controller does not allow creating content */ - $request = new WP_REST_Request( 'POST', '/wp/v2/search' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( 404, $response->get_status() ); - } - - /** - * Test updating an item isn't possible. - */ - public function test_update_item() { - /** The search controller does not allow upading content */ - $request = new WP_REST_Request( 'POST', '/wp/v2/search' . self::$my_title_post_ids[0] ); - $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( 404, $response->get_status() ); - } - - /** - * Test deleting an item isn't possible. - */ - public function test_delete_item() { - /** The search controller does not allow deleting content */ - $request = new WP_REST_Request( 'DELETE', '/wp/v2/search' . self::$my_title_post_ids[0] ); - $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( 404, $response->get_status() ); - } - - /** - * Test preparing the data contains the correct fields. - */ - public function test_prepare_item() { - $response = $this->do_request_with_params(); - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( - array( - 'id', - 'title', - 'url', - 'type', - 'subtype', - '_links', - ), - array_keys( $data[0] ) - ); - } - - /** - * Test preparing the data with limited fields contains the correct fields. - */ - public function test_prepare_item_limit_fields() { - if ( ! method_exists( 'WP_REST_Controller', 'get_fields_for_response' ) ) { - $this->markTestSkipped( 'Limiting fields requires the WP_REST_Controller::get_fields_for_response() method.' ); - } - - $response = $this->do_request_with_params( - array( - '_fields' => 'id,title', - ) - ); - $this->assertEquals( 200, $response->get_status() ); - - $data = $response->get_data(); - $this->assertEquals( - array( - 'id', - 'title', - '_links', - ), - array_keys( $data[0] ) - ); - } - - /** - * Tests the item schema is correct. - */ - public function test_get_item_schema() { - $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/search' ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - $properties = $data['schema']['properties']; - - $this->assertArrayHasKey( 'id', $properties ); - $this->assertArrayHasKey( 'title', $properties ); - $this->assertArrayHasKey( 'url', $properties ); - $this->assertArrayHasKey( 'type', $properties ); - $this->assertArrayHasKey( 'subtype', $properties ); - } - - /** - * Tests that non-public post types are not allowed. - */ - public function test_non_public_post_type() { - $response = $this->do_request_with_params( - array( - 'type' => 'post', - 'subtype' => 'post,nav_menu_item', - ) - ); - $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); - } - - /** - * Test getting items directly with a custom search handler. - */ - public function test_custom_search_handler_get_items() { - $controller = new WP_REST_Search_Controller( array( new WP_REST_Dummy_Search_Handler( 10 ) ) ); - - $request = $this->get_request( - array( - 'page' => 1, - 'per_page' => 10, - 'type' => 'dummy', - 'subtype' => array( WP_REST_Search_Controller::TYPE_ANY ), - ) - ); - $response = $controller->get_items( $request ); - $this->assertEqualSets( range( 1, 10 ), wp_list_pluck( $response->get_data(), 'id' ) ); - - $request = $this->get_request( - array( - 'page' => 1, - 'per_page' => 10, - 'type' => 'dummy', - 'subtype' => array( 'dummy_first_type' ), - ) - ); - $response = $controller->get_items( $request ); - $this->assertEqualSets( range( 1, 5 ), wp_list_pluck( $response->get_data(), 'id' ) ); - } - - /** - * Test preparing an item directly with a custom search handler. - */ - public function test_custom_search_handler_prepare_item() { - $controller = new WP_REST_Search_Controller( array( new WP_REST_Dummy_Search_Handler( 10 ) ) ); - - $request = $this->get_request( - array( - 'type' => 'dummy', - 'subtype' => array( WP_REST_Search_Controller::TYPE_ANY ), - ) - ); - $response = $controller->prepare_item_for_response( 1, $request ); - $data = $response->get_data(); - $this->assertEquals( - array( - 'id', - 'title', - 'url', - 'type', - 'subtype', - ), - array_keys( $data ) - ); - } - - /** - * Test preparing an item directly with a custom search handler with limited fields. - */ - public function test_custom_search_handler_prepare_item_limit_fields() { - if ( ! method_exists( 'WP_REST_Controller', 'get_fields_for_response' ) ) { - $this->markTestSkipped( 'Limiting fields requires the WP_REST_Controller::get_fields_for_response() method.' ); - } - - $controller = new WP_REST_Search_Controller( array( new WP_REST_Dummy_Search_Handler( 10 ) ) ); - - $request = $this->get_request( - array( - 'type' => 'dummy', - 'subtype' => array( WP_REST_Search_Controller::TYPE_ANY ), - '_fields' => 'id,title', - ) - ); - $response = $controller->prepare_item_for_response( 1, $request ); - $data = $response->get_data(); - $this->assertEquals( - array( - 'id', - 'title', - ), - array_keys( $data ) - ); - } - - /** - * Test getting the collection params directly with a custom search handler. - */ - public function test_custom_search_handler_get_collection_params() { - $controller = new WP_REST_Search_Controller( array( new WP_REST_Dummy_Search_Handler( 10 ) ) ); - - $params = $controller->get_collection_params(); - $this->assertEquals( 'dummy', $params[ WP_REST_Search_Controller::PROP_TYPE ]['default'] ); - $this->assertEqualSets( array( 'dummy' ), $params[ WP_REST_Search_Controller::PROP_TYPE ]['enum'] ); - $this->assertEqualSets( array( 'dummy_first_type', 'dummy_second_type', WP_REST_Search_Controller::TYPE_ANY ), $params[ WP_REST_Search_Controller::PROP_SUBTYPE ]['items']['enum'] ); - } - - /** - * Perform a REST request to our search endpoint with given parameters. - */ - private function do_request_with_params( $params = array(), $method = 'GET' ) { - $request = $this->get_request( $params, $method ); - - return rest_get_server()->dispatch( $request ); - } - - /** - * Get a REST request object for given parameters. - */ - private function get_request( $params = array(), $method = 'GET' ) { - $request = new WP_REST_Request( $method, '/wp/v2/search' ); - - foreach ( $params as $param => $value ) { - $request->set_param( $param, $value ); - } - - return $request; - } -} diff --git a/test/e2e/specs/__snapshots__/rich-text.test.js.snap b/test/e2e/specs/__snapshots__/rich-text.test.js.snap index e911f407edd680..275080b436f2da 100644 --- a/test/e2e/specs/__snapshots__/rich-text.test.js.snap +++ b/test/e2e/specs/__snapshots__/rich-text.test.js.snap @@ -24,6 +24,12 @@ exports[`RichText should handle change in tag name gracefully 1`] = ` " `; +exports[`RichText should only mutate text data on input 1`] = ` +" +1234
+" +`; + exports[`RichText should transform backtick to code 1`] = ` "A backtick
Typing in a metabox
"`; diff --git a/test/e2e/specs/blocks/__snapshots__/classic.test.js.snap b/test/e2e/specs/blocks/__snapshots__/classic.test.js.snap new file mode 100644 index 00000000000000..a4461344bb4384 --- /dev/null +++ b/test/e2e/specs/blocks/__snapshots__/classic.test.js.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Classic should be inserted 1`] = `"test"`; diff --git a/test/e2e/specs/blocks/classic.test.js b/test/e2e/specs/blocks/classic.test.js new file mode 100644 index 00000000000000..f0b733b4a9947d --- /dev/null +++ b/test/e2e/specs/blocks/classic.test.js @@ -0,0 +1,73 @@ +/** + * External dependencies + */ +import path from 'path'; +import fs from 'fs'; +import os from 'os'; +import uuid from 'uuid/v4'; + +/** + * Internal dependencies + */ +import { + getEditedPostContent, + newPost, + insertBlock, + pressWithModifier, +} from '../../support/utils'; + +describe( 'Classic', () => { + beforeEach( async () => { + await newPost(); + } ); + + it( 'should be inserted', async () => { + await insertBlock( 'Classic' ); + // Wait for TinyMCE to initialise. + await page.waitForSelector( '.mce-content-body' ); + // Ensure there is focus. + await page.focus( '.mce-content-body' ); + await page.keyboard.type( 'test' ); + // Move focus away. + await pressWithModifier( 'shift', 'Tab' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'should insert media', async () => { + await insertBlock( 'Classic' ); + // Wait for TinyMCE to initialise. + await page.waitForSelector( '.mce-content-body' ); + // Ensure there is focus. + await page.focus( '.mce-content-body' ); + await page.keyboard.type( 'test' ); + + // Click the image button. + await page.waitForSelector( 'div[aria-label="Add Media"]' ); + await page.click( 'div[aria-label="Add Media"]' ); + + // Wait for media modal to appear and upload image. + await page.waitForSelector( '.media-modal input[type=file]' ); + const inputElement = await page.$( '.media-modal input[type=file]' ); + const testImagePath = path.join( __dirname, '..', '..', 'assets', '10x10_e2e_test_image_z9T8jK.png' ); + const filename = uuid(); + const tmpFileName = path.join( os.tmpdir(), filename + '.png' ); + fs.copyFileSync( testImagePath, tmpFileName ); + await inputElement.uploadFile( tmpFileName ); + + // Wait for upload. + await page.waitForSelector( `.media-modal li[aria-label="${ filename }"]` ); + + // Insert the uploaded image. + await page.click( '.media-modal button.media-button-insert' ); + + // Wait for image to be inserted. + await page.waitForSelector( '.mce-content-body img' ); + + // Move focus away. + await pressWithModifier( 'shift', 'Tab' ); + + const regExp = new RegExp( `test` ); + expect( await getEditedPostContent() ).toMatch( regExp ); + } ); +} ); diff --git a/test/e2e/specs/classic-editor.test.js b/test/e2e/specs/classic-editor.test.js deleted file mode 100644 index 0d51c93e5b3420..00000000000000 --- a/test/e2e/specs/classic-editor.test.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Internal dependencies - */ -import { visitAdmin } from '../support/utils'; - -describe( 'classic editor', () => { - beforeAll( async () => { - await visitAdmin( 'post-new.php', 'classic-editor' ); - } ); - - it( 'Should work properly', async () => { - // Click visual editor - await expect( page ).toClick( '#content-tmce' ); - await expect( page ).toClick( '#content_ifr' ); - - // type some random text - await page.keyboard.type( 'Typing in classic editor' ); - - // Switch to HTML mode - await expect( page ).toClick( '#content-html' ); - - const textEditorContent = await page.$eval( '.wp-editor-area', ( element ) => element.value ); - expect( textEditorContent ).toEqual( 'Typing in classic editor' ); - } ); -} ); diff --git a/test/e2e/specs/font-size-picker.test.js b/test/e2e/specs/font-size-picker.test.js index 4a55dd3e0dbc83..42bfe7e17f5a49 100644 --- a/test/e2e/specs/font-size-picker.test.js +++ b/test/e2e/specs/font-size-picker.test.js @@ -5,6 +5,7 @@ import { clickBlockAppender, getEditedPostContent, newPost, + pressTimes, } from '../support/utils'; describe( 'Font Size Picker', () => { @@ -32,7 +33,8 @@ describe( 'Font Size Picker', () => { await page.keyboard.type( 'Paragraph to be made "small"' ); await page.click( '.blocks-font-size .components-range-control__number' ); - await page.keyboard.type( '13' ); + // This should be the "small" font-size of the current theme. + await page.keyboard.type( '19.5' ); // Ensure content matches snapshot. const content = await getEditedPostContent(); @@ -58,7 +60,8 @@ describe( 'Font Size Picker', () => { await page.keyboard.type( 'Paragraph with font size reset using button' ); await page.click( '.blocks-font-size .components-range-control__number' ); - await page.keyboard.type( '13' ); + // This should be the default font-size of the current theme. + await page.keyboard.type( '22' ); // Blur the range control await page.click( '.components-base-control__label' ); @@ -80,9 +83,10 @@ describe( 'Font Size Picker', () => { const changeSizeButton = await page.waitForSelector( '.components-button.is-font-large' ); await changeSizeButton.click(); + // Clear the custom font size input. await page.click( '.blocks-font-size .components-range-control__number' ); - await page.keyboard.press( 'Backspace' ); - await page.keyboard.press( 'Backspace' ); + await pressTimes( 'ArrowRight', 4 ); + await pressTimes( 'Backspace', 4 ); // Ensure content matches snapshot. const content = await getEditedPostContent(); diff --git a/test/e2e/specs/new-post.test.js b/test/e2e/specs/new-post.test.js index da171371330db4..44e08f1902f2dd 100644 --- a/test/e2e/specs/new-post.test.js +++ b/test/e2e/specs/new-post.test.js @@ -2,12 +2,19 @@ * Internal dependencies */ import { newPost } from '../support/utils'; +import { activatePlugin, deactivatePlugin } from '../support/plugins'; describe( 'new editor state', () => { beforeAll( async () => { + await activatePlugin( 'gutenberg-test-plugin-post-formats-support' ); await newPost(); } ); + afterAll( async () => { + await newPost(); + await deactivatePlugin( 'gutenberg-test-plugin-post-formats-support' ); + } ); + it( 'should show the New Post page in Gutenberg', async () => { expect( page.url() ).toEqual( expect.stringContaining( 'post-new.php' ) ); // Should display the blank title. diff --git a/test/e2e/specs/rich-text.test.js b/test/e2e/specs/rich-text.test.js index dca248c8289314..2f1012766444fd 100644 --- a/test/e2e/specs/rich-text.test.js +++ b/test/e2e/specs/rich-text.test.js @@ -67,4 +67,75 @@ describe( 'RichText', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); + + it( 'should only mutate text data on input', async () => { + await clickBlockAppender(); + await page.keyboard.type( '1' ); + await pressWithModifier( 'primary', 'b' ); + await page.keyboard.type( '2' ); + await pressWithModifier( 'primary', 'b' ); + await page.keyboard.type( '3' ); + + await page.evaluate( () => { + let called; + const { body } = document; + const config = { + attributes: true, + childList: true, + characterData: true, + subtree: true, + }; + + const mutationObserver = new MutationObserver( ( records ) => { + if ( called || records.length > 1 ) { + throw new Error( 'Typing should only mutate once.' ); + } + + records.forEach( ( record ) => { + if ( record.type !== 'characterData' ) { + throw new Error( + `Typing mutated more than character data: ${ record.type }` + ); + } + } ); + + called = true; + } ); + + mutationObserver.observe( body, config ); + + window.unsubscribes = [ () => mutationObserver.disconnect() ]; + + document.addEventListener( 'selectionchange', () => { + function throwMultipleSelectionChange() { + throw new Error( 'Typing should only emit one selection change event.' ); + } + + document.addEventListener( + 'selectionchange', + throwMultipleSelectionChange, + { once: true } + ); + + window.unsubscribes.push( () => { + document.removeEventListener( 'selectionchange', throwMultipleSelectionChange ); + } ); + }, { once: true } ); + } ); + + await page.keyboard.type( '4' ); + + await page.evaluate( () => { + // The selection change event should be called once. If there's only + // one item in `window.unsubscribes`, it means that only one + // function is present to disconnect the `mutationObserver`. + if ( window.unsubscribes.length === 1 ) { + throw new Error( 'The selection change event listener was never called.' ); + } + + window.unsubscribes.forEach( ( unsubscribe ) => unsubscribe() ); + } ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); } ); diff --git a/test/e2e/specs/templates.test.js b/test/e2e/specs/templates.test.js index 9b5d22080e0d42..4d8d16e9ce9513 100644 --- a/test/e2e/specs/templates.test.js +++ b/test/e2e/specs/templates.test.js @@ -72,8 +72,14 @@ describe( 'templates', () => { await switchToTestUser(); } - beforeAll( async () => await setPostFormat( 'image' ) ); - afterAll( async () => await setPostFormat( STANDARD_FORMAT_VALUE ) ); + beforeAll( async () => { + await activatePlugin( 'gutenberg-test-plugin-post-formats-support' ); + await setPostFormat( 'image' ); + } ); + afterAll( async () => { + await setPostFormat( STANDARD_FORMAT_VALUE ); + await deactivatePlugin( 'gutenberg-test-plugin-post-formats-support' ); + } ); it( 'should populate new post with default block for format', async () => { await newPost(); diff --git a/test/e2e/specs/wp-editor-meta-box.test.js b/test/e2e/specs/wp-editor-meta-box.test.js new file mode 100644 index 00000000000000..496057bb55c1cf --- /dev/null +++ b/test/e2e/specs/wp-editor-meta-box.test.js @@ -0,0 +1,38 @@ +/** + * Internal dependencies + */ +import { newPost, publishPost } from '../support/utils'; +import { activatePlugin, deactivatePlugin } from '../support/plugins'; + +describe( 'WP Editor Meta Boxes', () => { + beforeAll( async () => { + await activatePlugin( 'gutenberg-test-plugin-wp-editor-meta-box' ); + await newPost(); + } ); + + afterAll( async () => { + await deactivatePlugin( 'gutenberg-test-plugin-wp-editor-meta-box' ); + } ); + + it( 'Should save the changes', async () => { + // Add title to enable valid non-empty post save. + await page.type( '.editor-post-title__input', 'Hello Meta' ); + + // Type something + await page.click( '#test_tinymce_id-html' ); + await page.type( '#test_tinymce_id', 'Typing in a metabox' ); + await page.click( '#test_tinymce_id-tmce' ); + + await publishPost(); + + await page.reload(); + + await page.click( '#test_tinymce_id-html' ); + const content = await page.$eval( + '#test_tinymce_id', + ( textarea ) => textarea.value + ); + + expect( content ).toMatchSnapshot(); + } ); +} ); diff --git a/test/e2e/specs/writing-flow.test.js b/test/e2e/specs/writing-flow.test.js index bcad1f3d55bb0c..7c4197755bab81 100644 --- a/test/e2e/specs/writing-flow.test.js +++ b/test/e2e/specs/writing-flow.test.js @@ -44,6 +44,8 @@ describe( 'adding blocks', () => { // Arrow up in inner blocks should navigate through (1) column wrapper, // (2) text fields. + // We need to arrow up key presses in the paragraph block because it shows up in two lines. + await page.keyboard.press( 'ArrowUp' ); await page.keyboard.press( 'ArrowUp' ); await page.keyboard.press( 'ArrowUp' ); activeElementText = await page.evaluate( () => document.activeElement.textContent ); @@ -53,6 +55,7 @@ describe( 'adding blocks', () => { // columns wrappers before escaping out. let activeElementBlockType; await page.keyboard.press( 'ArrowUp' ); + await page.keyboard.press( 'ArrowUp' ); activeElementBlockType = await page.evaluate( () => ( document.activeElement.getAttribute( 'data-type' ) ) ); diff --git a/test/e2e/support/plugins.js b/test/e2e/support/plugins.js index da9edd3656860f..f8d64a7a1ec175 100644 --- a/test/e2e/support/plugins.js +++ b/test/e2e/support/plugins.js @@ -11,7 +11,7 @@ import { visitAdmin, switchToAdminUser, switchToTestUser } from './utils'; */ export async function installPlugin( slug, searchTerm ) { await switchToAdminUser(); - await visitAdmin( 'plugin-install.php?s=' + encodeURIComponent( searchTerm || slug ) + '&tab=search&type=term' ); + await visitAdmin( 'plugin-install.php', 's=' + encodeURIComponent( searchTerm || slug ) + '&tab=search&type=term' ); await page.click( '.install-now[data-slug="' + slug + '"]' ); await page.waitForSelector( '.activate-now[data-slug="' + slug + '"]' ); await switchToTestUser(); diff --git a/test/e2e/test-plugins/post-formats.php b/test/e2e/test-plugins/post-formats.php new file mode 100644 index 00000000000000..b0fdec68947fcb --- /dev/null +++ b/test/e2e/test-plugins/post-formats.php @@ -0,0 +1,15 @@ +ID, 'test_tinymce', true ); + wp_editor( $field_value, 'test_tinymce_id', array( + 'wpautop' => true, + 'media_buttons' => false, + 'textarea_name' => 'test_tinymce', + 'textarea_rows' => 10, + 'teeny' => true + ) ); + }, null, 'advanced', 'high' ); +}); +add_action( 'save_post', function( $post_id ){ + if ( ! isset( $_POST['test_tinymce'] ) ) { + return; + } + update_post_meta( $post_id, 'test_tinymce', $_POST['test_tinymce'] ); +});