From df1aa5f490a17c93d444141375e6721949ce3656 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 21 Mar 2022 11:46:35 +0000 Subject: [PATCH] Selector and associated tests --- packages/block-editor/src/store/selectors.js | 23 +++++++ .../block-editor/src/store/test/selectors.js | 63 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 5a88b6fb09b0ae..d9b6f2e212bec5 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -278,6 +278,29 @@ export const getGlobalBlockCount = createSelector( ( state ) => [ state.blocks.order, state.blocks.byClientId ] ); +/** + * Returns all global blocks that match a blockName. Results include nested blocks. + * + * @param {Object} state Global application state. + * @param {?string} blockName Optional block name, if not specified, returns an empty array. + * + * @return {Array} Array of clientIds of blocks with name equal to blockName. + */ +export const __experimentalGetGlobalBlocksByName = createSelector( + ( state, blockName ) => { + if ( ! blockName ) { + return EMPTY_ARRAY; + } + const clientIds = getClientIdsWithDescendants( state ); + const foundBlocks = clientIds.filter( ( clientId ) => { + const block = state.blocks.byClientId[ clientId ]; + return block.name === blockName; + } ); + return foundBlocks.length > 0 ? foundBlocks : EMPTY_ARRAY; + }, + ( state ) => [ state.blocks.order, state.blocks.byClientId ] +); + /** * Given an array of block client IDs, returns the corresponding array of block * objects. diff --git a/packages/block-editor/src/store/test/selectors.js b/packages/block-editor/src/store/test/selectors.js index a9baaec53d3468..1a6d496df0e49c 100644 --- a/packages/block-editor/src/store/test/selectors.js +++ b/packages/block-editor/src/store/test/selectors.js @@ -77,6 +77,7 @@ const { __unstableGetClientIdsTree, __experimentalGetPatternTransformItems, wasBlockJustInserted, + __experimentalGetGlobalBlocksByName, } = selectors; describe( 'selectors', () => { @@ -797,6 +798,68 @@ describe( 'selectors', () => { } ); } ); + describe( '__experimentalGetGlobalBlocksByName', () => { + const state = { + blocks: { + byClientId: { + 123: { clientId: 123, name: 'core/heading' }, + 456: { clientId: 456, name: 'core/paragraph' }, + 789: { clientId: 789, name: 'core/paragraph' }, + 1011: { clientId: 1011, name: 'core/group' }, + 1213: { clientId: 1213, name: 'core/paragraph' }, + 1415: { clientId: 1213, name: 'core/paragraph' }, + }, + attributes: { + 123: {}, + 456: {}, + 789: {}, + 1011: {}, + 1213: {}, + 1415: {}, + }, + order: { + '': [ 123, 456, 1011 ], + 1011: [ 1415, 1213 ], + }, + parents: { + 123: '', + 456: '', + 1011: '', + 1213: 1011, + 1415: 1011, + }, + }, + }; + + it( 'should return the clientIds of blocks of a given type', () => { + expect( + __experimentalGetGlobalBlocksByName( state, 'core/heading' ) + ).toStrictEqual( [ 123 ] ); + } ); + + it( 'should return the clientIds of blocks of a given type even if blocks are nested', () => { + expect( + __experimentalGetGlobalBlocksByName( state, 'core/paragraph' ) + ).toStrictEqual( [ 456, 1415, 1213 ] ); + } ); + + it( 'Should return empty array if no blocks match. The empty array should be the same reference', () => { + const result = __experimentalGetGlobalBlocksByName( + state, + 'test/missing' + ); + expect( + __experimentalGetGlobalBlocksByName( state, 'test/missing' ) + ).toStrictEqual( [] ); + expect( + __experimentalGetGlobalBlocksByName( + state, + 'test/missing2' + ) === result + ).toBe( true ); + } ); + } ); + describe( 'getSelectedBlockClientId', () => { it( 'should return null if no block is selected', () => { const state = {