-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
E2E Tests: Add Block Hooks Test Coverage #69044
base: trunk
Are you sure you want to change the base?
Changes from all commits
21a9d8c
983508a
20e1ff8
68fee6c
eed4fe0
1b19968
5d93287
a1f8bcb
61a8c8e
0fbdcc0
60d9a2d
0a941c6
7983d01
7a80350
47f6bec
14f5059
89645cc
2b9f127
dda5ea0
9b2ee0e
2b97811
dd7a644
70bcc01
8eb1de1
a757d56
acead15
92e7ff4
fe75a0d
4615325
495e14a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<?php | ||
/** | ||
* Plugin Name: Gutenberg Test Block Hooks | ||
* Plugin URI: https://github.com/WordPress/gutenberg | ||
* Author: Gutenberg Team | ||
* | ||
* @package gutenberg-test-block-hooks | ||
*/ | ||
|
||
defined( 'ABSPATH' ) || exit; | ||
|
||
function gutenberg_test_insert_hooked_blocks( $hooked_blocks, $position, $anchor_block, $context ) { | ||
if ( ! $context instanceof WP_Post ) { | ||
return $hooked_blocks; | ||
} | ||
|
||
if ( | ||
( 'core/heading' === $anchor_block && 'after' === $position ) || | ||
( 'core/post-content' === $anchor_block && 'last_child' === $position ) || | ||
( 'core/block' === $anchor_block && 'last_child' === $position ) | ||
) { | ||
$hooked_blocks[] = 'core/paragraph'; | ||
} | ||
|
||
if ( 'core/navigation' === $anchor_block && 'first_child' === $position ) { | ||
$hooked_blocks[] = 'core/home-link'; | ||
} | ||
|
||
if ( 'core/navigation-link' === $anchor_block && 'after' === $position ) { | ||
$hooked_blocks[] = 'core/page-list'; | ||
} | ||
|
||
return $hooked_blocks; | ||
} | ||
add_filter( 'hooked_block_types', 'gutenberg_test_insert_hooked_blocks', 10, 4 ); | ||
|
||
function gutenberg_test_set_hooked_block_inner_html( $hooked_block, $hooked_block_type, $relative_position, $anchor_block ) { | ||
if ( | ||
( 'core/heading' === $anchor_block['blockName'] && 'after' === $relative_position ) || | ||
( 'core/post-content' === $anchor_block['blockName'] && 'last_child' === $relative_position ) || | ||
( 'core/block' === $anchor_block['blockName'] && 'last_child' === $relative_position ) | ||
) { | ||
$hooked_block['attrs'] = array( | ||
'className' => "hooked-block-{$relative_position}-" . str_replace( 'core/', '', $anchor_block['blockName'] ), | ||
); | ||
$hooked_block['innerContent'] = array( | ||
sprintf( | ||
'<p class="%1$s">This block was inserted by the Block Hooks API in the <code>%2$s</code> position next to the <code>%3$s</code> anchor block.</p>', | ||
$hooked_block['attrs']['className'], | ||
$relative_position, | ||
$anchor_block['blockName'] | ||
), | ||
); | ||
} | ||
|
||
return $hooked_block; | ||
} | ||
add_filter( 'hooked_block_core/paragraph', 'gutenberg_test_set_hooked_block_inner_html', 10, 4 ); | ||
|
||
function gutenberg_register_wp_ignored_hooked_blocks_meta() { | ||
register_post_meta( | ||
'post', | ||
'_wp_ignored_hooked_blocks', | ||
array( | ||
'show_in_rest' => true, | ||
'single' => true, | ||
'type' => 'string', | ||
'auth_callback' => function () { | ||
return current_user_can( 'edit_posts' ); | ||
}, | ||
) | ||
); | ||
} | ||
add_action( 'rest_api_init', 'gutenberg_register_wp_ignored_hooked_blocks_meta' ); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,292 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); | ||
|
||
const dummyBlockContent = `<!-- wp:heading --> | ||
<h2 class="wp-block-heading">This is a dummy heading</h2> | ||
<!-- /wp:heading --> | ||
<!-- wp:paragraph {"className":"dummy-paragraph"} --> | ||
<p class="dummy-paragraph">This is a dummy paragraph.</p> | ||
<!-- /wp:paragraph -->`; | ||
|
||
const getHookedBlockClassName = ( relativePosition, anchorBlock ) => | ||
`hooked-block-${ relativePosition }-${ anchorBlock.replace( | ||
'core/', | ||
'' | ||
) }`; | ||
|
||
const getHookedBlockContent = ( relativePosition, anchorBlock ) => | ||
`This block was inserted by the Block Hooks API in the ${ relativePosition } position next to the ${ anchorBlock } anchor block.`; | ||
|
||
test.describe( 'Block Hooks API', () => { | ||
[ | ||
{ | ||
name: 'Post Content', | ||
postType: 'post', | ||
blockType: 'core/post-content', | ||
createMethod: 'createPost', | ||
}, | ||
{ | ||
name: 'Synced Pattern', | ||
postType: 'wp_block', | ||
blockType: 'core/block', | ||
createMethod: 'createBlock', | ||
}, | ||
].forEach( ( { name, postType, blockType, createMethod } ) => { | ||
test.describe( `Hooked blocks in ${ name }`, () => { | ||
let postObject, containerPost; | ||
test.beforeAll( async ( { requestUtils } ) => { | ||
postObject = await requestUtils[ createMethod ]( { | ||
title: name, | ||
status: 'publish', | ||
content: dummyBlockContent, | ||
} ); | ||
|
||
await requestUtils.activatePlugin( | ||
'gutenberg-test-block-hooks' | ||
); | ||
|
||
if ( postType !== 'post' ) { | ||
// We need a container post to hold our block instance. | ||
containerPost = await requestUtils.createPost( { | ||
title: `Block Hooks in ${ name }`, | ||
status: 'publish', | ||
content: `<!-- wp:${ blockType } {"ref":${ postObject.id }} /-->`, | ||
meta: { | ||
// Prevent Block Hooks from injecting blocks into the container | ||
// post content so they won't distract from the ones injected | ||
// into the block instance. | ||
_wp_ignored_hooked_blocks: '["core/paragraph"]', | ||
}, | ||
} ); | ||
} else { | ||
containerPost = postObject; | ||
} | ||
} ); | ||
|
||
test.afterAll( async ( { requestUtils } ) => { | ||
await requestUtils.deactivatePlugin( | ||
'gutenberg-test-block-hooks' | ||
); | ||
|
||
await requestUtils.deleteAllPosts(); | ||
await requestUtils.deleteAllBlocks(); | ||
} ); | ||
|
||
test( `should insert hooked blocks into ${ name } on frontend`, async ( { | ||
page, | ||
} ) => { | ||
await page.goto( `/?p=${ containerPost.id }` ); | ||
await expect( | ||
page.locator( '.entry-content > *' ) | ||
).toHaveClass( [ | ||
'wp-block-heading', | ||
getHookedBlockClassName( 'after', 'core/heading' ), | ||
'dummy-paragraph', | ||
getHookedBlockClassName( 'last_child', blockType ), | ||
] ); | ||
} ); | ||
|
||
test( `should insert hooked blocks into ${ name } in editor and respect changes made there`, async ( { | ||
admin, | ||
editor, | ||
page, | ||
} ) => { | ||
const expectedHookedBlockAfterHeading = { | ||
name: 'core/paragraph', | ||
attributes: { | ||
className: getHookedBlockClassName( | ||
'after', | ||
'core/heading' | ||
), | ||
}, | ||
}; | ||
|
||
const expectedHookedBlockLastChild = { | ||
name: 'core/paragraph', | ||
attributes: { | ||
className: getHookedBlockClassName( | ||
'last_child', | ||
blockType | ||
), | ||
}, | ||
}; | ||
|
||
await admin.editPost( postObject.id ); | ||
await expect | ||
.poll( editor.getBlocks ) | ||
.toMatchObject( [ | ||
{ name: 'core/heading' }, | ||
expectedHookedBlockAfterHeading, | ||
{ name: 'core/paragraph' }, | ||
expectedHookedBlockLastChild, | ||
] ); | ||
|
||
const hookedBlock = editor.canvas.getByText( | ||
getHookedBlockContent( 'last_child', blockType ) | ||
); | ||
await editor.selectBlocks( hookedBlock ); | ||
await editor.clickBlockToolbarButton( 'Move up' ); | ||
|
||
// Save updated post. | ||
const saveButton = page | ||
.getByRole( 'region', { name: 'Editor top bar' } ) | ||
.getByRole( 'button', { name: 'Save', exact: true } ); | ||
await saveButton.click(); | ||
await page | ||
.getByRole( 'button', { name: 'Dismiss this notice' } ) | ||
.filter( { hasText: 'updated' } ) | ||
.waitFor(); | ||
|
||
// Reload and verify that the new position of the hooked block has been persisted. | ||
await page.reload(); | ||
await expect | ||
.poll( editor.getBlocks ) | ||
.toMatchObject( [ | ||
{ name: 'core/heading' }, | ||
expectedHookedBlockAfterHeading, | ||
expectedHookedBlockLastChild, | ||
{ name: 'core/paragraph' }, | ||
] ); | ||
|
||
// Verify that the frontend reflects the changes made in the editor. | ||
await page.goto( `/?p=${ containerPost.id }` ); | ||
await expect( | ||
page.locator( '.entry-content > *' ) | ||
).toHaveClass( [ | ||
'wp-block-heading', | ||
getHookedBlockClassName( 'after', 'core/heading' ), | ||
getHookedBlockClassName( 'last_child', blockType ), | ||
'dummy-paragraph', | ||
] ); | ||
} ); | ||
} ); | ||
} ); | ||
|
||
test.describe( `Hooked blocks in Navigation Menu`, () => { | ||
let postObject, containerPost; | ||
test.beforeAll( async ( { requestUtils } ) => { | ||
postObject = await requestUtils.createNavigationMenu( { | ||
title: 'Navigation Menu', | ||
status: 'publish', | ||
content: | ||
'<!-- wp:navigation-link {"label":"wordpress.org","url":"https://wordpress.org","kind":"custom"} /-->', // '<!-- wp:page-list /-->', | ||
} ); | ||
|
||
await requestUtils.activatePlugin( 'gutenberg-test-block-hooks' ); | ||
|
||
// We need a container post to hold our block instance. | ||
containerPost = await requestUtils.createPost( { | ||
title: `Block Hooks in Navigation Menu`, | ||
status: 'publish', | ||
content: `<!-- wp:navigation {"ref":${ postObject.id }} /-->`, | ||
meta: { | ||
// Prevent Block Hooks from injecting blocks into the container | ||
// post content so they won't distract from the ones injected | ||
// into the block instance. | ||
_wp_ignored_hooked_blocks: '["core/paragraph"]', | ||
}, | ||
} ); | ||
} ); | ||
|
||
test.afterAll( async ( { requestUtils } ) => { | ||
await requestUtils.deactivatePlugin( 'gutenberg-test-block-hooks' ); | ||
|
||
await requestUtils.deleteAllPosts(); | ||
await requestUtils.deleteAllBlocks(); | ||
} ); | ||
|
||
test( `should insert hooked blocks into Navigation Menu on frontend`, async ( { | ||
page, | ||
} ) => { | ||
await page.goto( `/?p=${ containerPost.id }` ); | ||
await expect( | ||
page.locator( '.wp-block-navigation__container > *' ) | ||
).toHaveClass( [ | ||
Check failure on line 206 in test/e2e/specs/editor/plugins/block-hooks.spec.js
|
||
'wp-block-navigation-item wp-block-home-link', | ||
' wp-block-navigation-item wp-block-navigation-link', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this preceding space intentional? |
||
'wp-block-page-list', | ||
] ); | ||
} ); | ||
|
||
test( `should insert hooked blocks into Navigation Menu in editor and respect changes made there`, async ( { | ||
admin, | ||
editor, | ||
page, | ||
} ) => { | ||
await admin.visitSiteEditor( { | ||
postId: postObject.id, | ||
postType: 'wp_navigation', | ||
canvas: 'edit', | ||
} ); | ||
|
||
// Since the Navigation block is a controlled block, we need | ||
// to specify its client ID when calling `getBlocks`. | ||
let navigationBlock = editor.canvas.getByRole( 'document', { | ||
name: 'Block: Navigation', | ||
} ); | ||
let navigationClientId = | ||
await navigationBlock.getAttribute( 'data-block' ); | ||
|
||
await expect | ||
.poll( () => | ||
editor.getBlocks( { | ||
clientId: navigationClientId, | ||
} ) | ||
) | ||
.toMatchObject( [ | ||
{ name: 'core/home-link' }, | ||
{ name: 'core/navigation-link' }, | ||
{ name: 'core/page-list' }, | ||
] ); | ||
|
||
const hookedBlock = editor.canvas.getByRole( 'document', { | ||
name: 'Block: Home Link', | ||
} ); | ||
await editor.selectBlocks( hookedBlock ); | ||
await editor.clickBlockToolbarButton( 'Move right' ); | ||
|
||
// Save updated post. | ||
const saveButton = page | ||
.getByRole( 'region', { name: 'Editor top bar' } ) | ||
.getByRole( 'button', { name: 'Save', exact: true } ); | ||
await saveButton.click(); | ||
await page | ||
.getByRole( 'button', { name: 'Dismiss this notice' } ) | ||
.filter( { hasText: 'updated' } ) | ||
.waitFor(); | ||
|
||
// Reload and verify that the new position of the hooked block has been persisted. | ||
await page.reload(); | ||
|
||
navigationBlock = editor.canvas.getByRole( 'document', { | ||
name: 'Block: Navigation', | ||
} ); | ||
navigationClientId = | ||
await navigationBlock.getAttribute( 'data-block' ); | ||
|
||
await expect | ||
.poll( () => | ||
editor.getBlocks( { | ||
clientId: navigationClientId, | ||
} ) | ||
) | ||
.toMatchObject( [ | ||
{ name: 'core/navigation-link' }, | ||
{ name: 'core/home-link' }, | ||
{ name: 'core/page-list' }, | ||
] ); | ||
|
||
// Verify that the frontend reflects the changes made in the editor. | ||
await page.goto( `/?p=${ containerPost.id }` ); | ||
await expect( | ||
page.locator( '.wp-block-navigation__container > *' ) | ||
).toHaveClass( [ | ||
Check failure on line 285 in test/e2e/specs/editor/plugins/block-hooks.spec.js
|
||
' wp-block-navigation-item wp-block-navigation-link', | ||
'wp-block-navigation-item wp-block-home-link', | ||
'wp-block-page-list', | ||
] ); | ||
} ); | ||
} ); | ||
} ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there a code comment with a different block included?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two failing tests might be related to that: