diff --git a/src/experiments/title-generation/components/TitleToolbar.tsx b/src/experiments/title-generation/components/TitleToolbar.tsx index 6464e4afa..2d75682a3 100644 --- a/src/experiments/title-generation/components/TitleToolbar.tsx +++ b/src/experiments/title-generation/components/TitleToolbar.tsx @@ -14,7 +14,7 @@ import { ToolbarGroup, ToolbarButton, } from '@wordpress/components'; -import { dispatch, select, useDispatch } from '@wordpress/data'; +import { dispatch, useDispatch, useSelect } from '@wordpress/data'; import { store as editorStore, PostTypeSupportCheck } from '@wordpress/editor'; import { useState } from '@wordpress/element'; import { update } from '@wordpress/icons'; @@ -78,8 +78,15 @@ interface TitleToolbarProps { export default function TitleToolbar( { isStandalone = false, }: TitleToolbarProps ): React.JSX.Element | null { - const postId = select( editorStore ).getCurrentPostId(); - const title = select( editorStore ).getEditedPostAttribute( 'title' ); + const { postId, content, title } = useSelect( ( select ) => { + const editor = select( editorStore ); + + return { + postId: editor.getCurrentPostId(), + content: editor.getEditedPostContent() || '', + title: editor.getEditedPostAttribute( 'title' ) || '', + }; + }, [] ); const { editPost } = useDispatch( editorStore ); @@ -94,6 +101,7 @@ export default function TitleToolbar( { setGeneratedTitle( '' ); }; + const hasContent = content.trim().length > 0; const hasTitle = title.trim().length > 0; let buttonLabel: string = __( 'Generate', 'ai' ); @@ -112,7 +120,6 @@ export default function TitleToolbar( { return; } - const content = select( editorStore ).getEditedPostContent(); setIsGenerating( true ); ( dispatch( noticesStore ) as any ).removeNotice( 'ai_title_generation_error' @@ -141,7 +148,6 @@ export default function TitleToolbar( { * Fetches a new suggestion without closing the modal. */ const handleRegenerate = async () => { - const content = select( editorStore ).getEditedPostContent(); setIsRegenerating( true ); ( dispatch( noticesStore ) as any ).removeNotice( 'ai_title_generation_error' @@ -172,8 +178,8 @@ export default function TitleToolbar( { closeModal(); }; - // Don't render if disabled. - if ( ! aiTitleGenerationData?.enabled ) { + // Don't render if disabled or there is no post content to generate from. + if ( ! aiTitleGenerationData?.enabled || ! hasContent ) { return null; } diff --git a/tests/e2e/specs/experiments/title-generation.spec.js b/tests/e2e/specs/experiments/title-generation.spec.js index 413c5eb31..8c1915169 100644 --- a/tests/e2e/specs/experiments/title-generation.spec.js +++ b/tests/e2e/specs/experiments/title-generation.spec.js @@ -95,6 +95,52 @@ test.describe( 'Title Generation Experiment', () => { await editor.saveDraft(); } ); + test( 'Only shows Title Generation after content exists', async ( { + admin, + editor, + page, + } ) => { + // Globally turn on Experiments. + await enableExperiments( admin, page ); + + // Enable the Title Generation Experiment. + await enableExperiment( admin, page, 'Title Generation' ); + + // Create a new empty post. + await admin.createNewPost( { + postType: 'post', + title: '', + content: '', + } ); + + // Click into the title field. + await editor.canvas.locator( '.editor-post-title__input' ).click(); + + // Ensure the title toolbar is not visible before content exists. + await expect( + editor.canvas.locator( '.ai-title-toolbar-container button' ) + ).toHaveCount( 0 ); + + // Add content to the post body. + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { + content: + 'This is some test content for the Title Generation Experiment.', + }, + } ); + + // Refocus the title field. + await editor.canvas.locator( '.editor-post-title__input' ).click(); + + // Ensure the title toolbar is visible with "Generate" label. + await expect( + editor.canvas.locator( '.ai-title-toolbar-container', { + hasText: 'Generate', + } ) + ).toBeVisible(); + } ); + test( 'Can use the Title Generation Experiment with a post with a title', async ( { admin, editor,