diff --git a/src/hooks/tests/use-add-site.test.tsx b/src/hooks/tests/use-add-site.test.tsx index c56433daf6..a6bb28a349 100644 --- a/src/hooks/tests/use-add-site.test.tsx +++ b/src/hooks/tests/use-add-site.test.tsx @@ -23,18 +23,23 @@ jest.mock( 'src/hooks/use-import-export', () => ( { } ) ); const mockConnectWpcomSites = jest.fn().mockResolvedValue( undefined ); +const mockGenerateProposedSitePath = jest.fn().mockResolvedValue( { + path: '/default/path', + name: 'Default Site', + isEmpty: true, + isWordPress: false, +} ); + +const mockComparePaths = jest.fn().mockResolvedValue( false ); + jest.mock( 'src/lib/get-ipc-api', () => ( { getIpcApi: () => ( { - generateProposedSitePath: jest.fn().mockResolvedValue( { - path: '/default/path', - name: 'Default Site', - isEmpty: true, - isWordPress: false, - } ), + generateProposedSitePath: mockGenerateProposedSitePath, showNotification: jest.fn(), getAllCustomDomains: jest.fn().mockResolvedValue( [] ), connectWpcomSites: mockConnectWpcomSites, getConnectedWpcomSites: jest.fn().mockResolvedValue( [] ), + comparePaths: mockComparePaths, } ), } ) ); @@ -246,4 +251,56 @@ describe( 'useAddSite', () => { } ); expect( mockSetSelectedTab ).toHaveBeenCalledWith( 'sync' ); } ); + + describe( 'handleSiteNameChange', () => { + beforeEach( () => { + mockGenerateProposedSitePath.mockReset(); + mockGenerateProposedSitePath.mockResolvedValue( { + path: '/default/path', + name: 'Default Site', + isEmpty: true, + isWordPress: false, + } ); + mockComparePaths.mockReset(); + mockComparePaths.mockResolvedValue( false ); + } ); + + it( 'should set user-friendly error when site name causes ENAMETOOLONG error', async () => { + mockGenerateProposedSitePath.mockResolvedValueOnce( { + path: '/default/path/very-long-name', + name: 'a'.repeat( 300 ), + isEmpty: false, + isWordPress: false, + isNameTooLong: true, + } ); + + const { result } = renderHookWithProvider( () => useAddSite() ); + + await act( async () => { + await result.current.handleSiteNameChange( 'a'.repeat( 300 ) ); + } ); + + expect( result.current.error ).toBe( + 'The site name is too long. Please choose a shorter site name.' + ); + } ); + + it( 'should successfully update site name when path is valid', async () => { + mockGenerateProposedSitePath.mockResolvedValueOnce( { + path: '/default/path/my-site', + name: 'my-site', + isEmpty: true, + isWordPress: false, + } ); + + const { result } = renderHookWithProvider( () => useAddSite() ); + + await act( async () => { + await result.current.handleSiteNameChange( 'my-site' ); + } ); + + expect( result.current.siteName ).toBe( 'my-site' ); + expect( result.current.error ).toBe( '' ); + } ); + } ); } ); diff --git a/src/hooks/use-add-site.ts b/src/hooks/use-add-site.ts index 53afe155ed..a71fa23dc7 100644 --- a/src/hooks/use-add-site.ts +++ b/src/hooks/use-add-site.ts @@ -244,13 +244,20 @@ export function useAddSite( options: UseAddSiteOptions = {} ) { return; } setError( '' ); + const { path: proposedPath, isEmpty, isWordPress, + isNameTooLong, } = await getIpcApi().generateProposedSitePath( name ); setProposedSitePath( proposedPath ); + if ( isNameTooLong ) { + setError( __( 'The site name is too long. Please choose a shorter site name.' ) ); + return; + } + if ( await siteWithPathAlreadyExists( proposedPath ) ) { setError( __( diff --git a/src/ipc-handlers.ts b/src/ipc-handlers.ts index a9a4ebdcf3..69f7a9f038 100644 --- a/src/ipc-handlers.ts +++ b/src/ipc-handlers.ts @@ -450,6 +450,7 @@ export interface FolderDialogResponse { name: string; isEmpty: boolean; isWordPress: boolean; + isNameTooLong?: boolean; } export async function showSaveAsDialog( event: IpcMainInvokeEvent, options: SaveDialogOptions ) { @@ -713,6 +714,15 @@ export async function generateProposedSitePath( isWordPress: false, }; } + if ( isErrnoException( err ) && err.code === 'ENAMETOOLONG' ) { + return { + path, + name: siteName, + isEmpty: false, + isWordPress: false, + isNameTooLong: true, + }; + } throw err; } }