diff --git a/packages/block-library/src/navigation-link/shared/test/use-entity-binding.js b/packages/block-library/src/navigation-link/shared/test/use-entity-binding.js index 74bb603a05a699..62513e1d55b178 100644 --- a/packages/block-library/src/navigation-link/shared/test/use-entity-binding.js +++ b/packages/block-library/src/navigation-link/shared/test/use-entity-binding.js @@ -7,22 +7,21 @@ */ import { renderHook, act } from '@testing-library/react'; -/** - * WordPress dependencies - */ -import { useBlockBindingsUtils } from '@wordpress/block-editor'; - /** * Internal dependencies */ import { useEntityBinding } from '../use-entity-binding'; -// Mock the useBlockBindingsUtils hook +// Mock the entire @wordpress/block-editor module jest.mock( '@wordpress/block-editor', () => ( { - ...jest.requireActual( '@wordpress/block-editor' ), useBlockBindingsUtils: jest.fn(), } ) ); +/** + * WordPress dependencies + */ +import { useBlockBindingsUtils } from '@wordpress/block-editor'; + describe( 'useEntityBinding', () => { const mockUpdateBlockBindings = jest.fn(); @@ -33,23 +32,117 @@ describe( 'useEntityBinding', () => { } ); } ); - it( 'should return hasUrlBinding as false when no binding exists', () => { - const attributes = { - metadata: {}, - id: null, - }; + describe( 'hasUrlBinding', () => { + it( 'should return false when no binding exists', () => { + const attributes = { + metadata: {}, + id: null, + }; + + const { result } = renderHook( () => + useEntityBinding( { + clientId: 'test-client-id', + attributes, + } ) + ); + + expect( result.current.hasUrlBinding ).toBe( false ); + } ); - const { result } = renderHook( () => - useEntityBinding( { - clientId: 'test-client-id', - attributes, - } ) - ); + it( 'should return true when core/entity binding exists with id', () => { + const attributes = { + metadata: { + bindings: { + url: { + source: 'core/entity', + args: { key: 'url' }, + }, + }, + }, + id: 123, + }; + + const { result } = renderHook( () => + useEntityBinding( { + clientId: 'test-client-id', + attributes, + } ) + ); + + expect( result.current.hasUrlBinding ).toBe( true ); + } ); + + it( 'should return false when source is not core/entity', () => { + const attributes = { + metadata: { + bindings: { + url: { + source: 'some-other-source', + args: { key: 'url' }, + }, + }, + }, + id: 123, + }; + + const { result } = renderHook( () => + useEntityBinding( { + clientId: 'test-client-id', + attributes, + } ) + ); - expect( result.current.hasUrlBinding ).toBe( false ); + expect( result.current.hasUrlBinding ).toBe( false ); + } ); + + it( 'should return false when core/entity binding exists but no id', () => { + const attributes = { + metadata: { + bindings: { + url: { + source: 'core/entity', + args: { key: 'url' }, + }, + }, + }, + id: null, + }; + + const { result } = renderHook( () => + useEntityBinding( { + clientId: 'test-client-id', + attributes, + } ) + ); + + expect( result.current.hasUrlBinding ).toBe( false ); + } ); + + it( 'should return false when binding source is null', () => { + const attributes = { + metadata: { + bindings: { + url: { + source: null, + args: null, + }, + }, + }, + id: 123, + }; + + const { result } = renderHook( () => + useEntityBinding( { + clientId: 'test-client-id', + attributes, + } ) + ); + + expect( result.current.hasUrlBinding ).toBe( false ); + } ); } ); - it( 'should return hasUrlBinding as true when binding exists', () => { + it( 'should clear binding when clearBinding is called and binding exists', () => { const attributes = { metadata: { bindings: { @@ -69,16 +162,42 @@ describe( 'useEntityBinding', () => { } ) ); - expect( result.current.hasUrlBinding ).toBe( true ); + act( () => { + result.current.clearBinding(); + } ); + + expect( mockUpdateBlockBindings ).toHaveBeenCalledWith( { + url: undefined, + } ); + } ); + + it( 'should NOT clear binding when clearBinding is called and no binding exists', () => { + const attributes = { + metadata: {}, + id: null, + }; + + const { result } = renderHook( () => + useEntityBinding( { + clientId: 'test-client-id', + attributes, + } ) + ); + + act( () => { + result.current.clearBinding(); + } ); + + expect( mockUpdateBlockBindings ).not.toHaveBeenCalled(); } ); - it( 'should clear binding when clearBinding is called', () => { + it( 'should NOT clear binding when binding metadata exists but source is null', () => { const attributes = { metadata: { bindings: { url: { - source: 'core/entity', - args: { key: 'url' }, + source: null, + args: null, }, }, }, @@ -96,12 +215,7 @@ describe( 'useEntityBinding', () => { result.current.clearBinding(); } ); - expect( mockUpdateBlockBindings ).toHaveBeenCalledWith( { - url: { - source: null, - args: null, - }, - } ); + expect( mockUpdateBlockBindings ).not.toHaveBeenCalled(); } ); it( 'should create binding when createBinding is called', () => { diff --git a/packages/block-library/src/navigation-link/shared/use-entity-binding.js b/packages/block-library/src/navigation-link/shared/use-entity-binding.js index a07e77b3e84ddb..a24127d1004a31 100644 --- a/packages/block-library/src/navigation-link/shared/use-entity-binding.js +++ b/packages/block-library/src/navigation-link/shared/use-entity-binding.js @@ -19,16 +19,17 @@ export function useEntityBinding( { clientId, attributes } ) { const { updateBlockBindings } = useBlockBindingsUtils( clientId ); const { metadata, id } = attributes; - const hasUrlBinding = !! metadata?.bindings?.url && !! id; + // Check if there's a URL binding with the core/entity source + const hasUrlBinding = + metadata?.bindings?.url?.source === 'core/entity' && !! id; const clearBinding = useCallback( () => { - updateBlockBindings( { - url: { - source: null, - args: null, - }, - } ); - }, [ updateBlockBindings ] ); + // Only clear if there's actually a valid binding to clear + if ( hasUrlBinding ) { + // Remove the URL binding by setting it to undefined + updateBlockBindings( { url: undefined } ); + } + }, [ hasUrlBinding, updateBlockBindings ] ); const createBinding = useCallback( () => { updateBlockBindings( {