diff --git a/packages/block-editor/src/components/inner-blocks/use-inner-block-template-sync.js b/packages/block-editor/src/components/inner-blocks/use-inner-block-template-sync.js index 1b81069c44f3dc..c9ccfe7faaf0e4 100644 --- a/packages/block-editor/src/components/inner-blocks/use-inner-block-template-sync.js +++ b/packages/block-editor/src/components/inner-blocks/use-inner-block-template-sync.js @@ -42,7 +42,8 @@ export default function useInnerBlockTemplateSync( ) { const { getSelectedBlocksInitialCaretPosition, isBlockSelected } = useSelect( blockEditorStore ); - const { replaceInnerBlocks } = useDispatch( blockEditorStore ); + const { replaceInnerBlocks, __unstableMarkNextChangeAsNotPersistent } = + useDispatch( blockEditorStore ); const innerBlocks = useSelect( ( select ) => select( blockEditorStore ).getBlocks( clientId ), [ clientId ] @@ -81,6 +82,7 @@ export default function useInnerBlockTemplateSync( ); if ( ! isEqual( nextBlocks, currentInnerBlocks ) ) { + __unstableMarkNextChangeAsNotPersistent(); replaceInnerBlocks( clientId, nextBlocks, diff --git a/packages/e2e-tests/plugins/inner-blocks-templates/index.js b/packages/e2e-tests/plugins/inner-blocks-templates/index.js index 3d8630103f16a1..959f4a3eeb5a0b 100644 --- a/packages/e2e-tests/plugins/inner-blocks-templates/index.js +++ b/packages/e2e-tests/plugins/inner-blocks-templates/index.js @@ -3,6 +3,8 @@ const createBlock = wp.blocks.createBlock; const el = wp.element.createElement; const InnerBlocks = wp.blockEditor.InnerBlocks; + const useState = window.wp.element.useState; + const TEMPLATE = [ [ 'core/paragraph', @@ -171,4 +173,31 @@ save, } ); + + + function InnerBlocksAsyncTemplateEdit() { + const [ template, setTemplate ] = useState( [] ); + + setInterval( () => { + setTemplate( TEMPLATE_TWO_PARAGRAPHS ); + }, 1000 ); + + return el( InnerBlocks, { + template, + } ); + } + + registerBlockType( + 'test/test-inner-blocks-async-template', + { + title: 'Test Inner Blocks Async Template', + icon: 'cart', + category: 'text', + + edit: InnerBlocksAsyncTemplateEdit, + + // Purposely do not save inner blocks so that it's possible to test template resolution. + save() {}, + } + ); } )(); diff --git a/test/e2e/specs/editor/plugins/__snapshots__/templates-Using-a-CPT-with-a-predefined-templa-7538a--custom-post-types-with-a-predefined-template-1-chromium.txt b/test/e2e/specs/editor/plugins/__snapshots__/Post-type-templates-Using-a-CPT-with-a-predefi-fffe1--custom-post-types-with-a-predefined-template-1-chromium.txt similarity index 100% rename from test/e2e/specs/editor/plugins/__snapshots__/templates-Using-a-CPT-with-a-predefined-templa-7538a--custom-post-types-with-a-predefined-template-1-chromium.txt rename to test/e2e/specs/editor/plugins/__snapshots__/Post-type-templates-Using-a-CPT-with-a-predefi-fffe1--custom-post-types-with-a-predefined-template-1-chromium.txt diff --git a/test/e2e/specs/editor/plugins/templates.spec.js b/test/e2e/specs/editor/plugins/post-type-templates.spec.js similarity index 98% rename from test/e2e/specs/editor/plugins/templates.spec.js rename to test/e2e/specs/editor/plugins/post-type-templates.spec.js index bab5cdd739baf6..3c5a664259f2d2 100644 --- a/test/e2e/specs/editor/plugins/templates.spec.js +++ b/test/e2e/specs/editor/plugins/post-type-templates.spec.js @@ -3,7 +3,7 @@ */ const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); -test.describe( 'templates', () => { +test.describe( 'Post type templates', () => { test.describe( 'Using a CPT with a predefined template', () => { test.beforeAll( async ( { requestUtils } ) => { await requestUtils.activatePlugin( diff --git a/test/e2e/specs/editor/various/inner-blocks-templates.spec.js b/test/e2e/specs/editor/various/inner-blocks-templates.spec.js new file mode 100644 index 00000000000000..87ad2604281983 --- /dev/null +++ b/test/e2e/specs/editor/various/inner-blocks-templates.spec.js @@ -0,0 +1,56 @@ +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'Inner blocks templates', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activatePlugin( + 'gutenberg-test-inner-blocks-templates' + ); + } ); + + test.beforeEach( async ( { admin } ) => { + await admin.createNewPost(); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.deactivatePlugin( + 'gutenberg-test-inner-blocks-templates' + ); + } ); + + test( 'applying block templates asynchronously does not create a persistent change in the editor', async ( { + editor, + page, + } ) => { + await editor.insertBlock( { + name: 'test/test-inner-blocks-async-template', + } ); + + const blockWithTemplateContent = page.locator( + 'role=document[name="Block: Test Inner Blocks Async Template"i] >> text=OneTwo' + ); + + // The block template content appears asynchronously, so wait for it. + await expect( blockWithTemplateContent ).toBeVisible(); + + // Publish the post, then reload. + await editor.publishPost(); + await page.reload(); + + // Wait for the block that was inserted to appear with its templated content. + await expect( blockWithTemplateContent ).toBeVisible(); + + // The template resolution shouldn't cause the post to be dirty. + const editorTopBar = page.locator( + 'role=region[name="Editor top bar"i]' + ); + const undoButton = editorTopBar.locator( 'role=button[name="Undo"i]' ); + const updateButton = editorTopBar.locator( + 'role=button[name="Update"i]' + ); + await expect( undoButton ).toHaveAttribute( 'aria-disabled', 'true' ); + await expect( updateButton ).toHaveAttribute( 'aria-disabled', 'true' ); + } ); +} );