diff --git a/packages/data/src/redux-store/index.js b/packages/data/src/redux-store/index.js index 0395609eabca4..4ed82f50d816b 100644 --- a/packages/data/src/redux-store/index.js +++ b/packages/data/src/redux-store/index.js @@ -235,11 +235,24 @@ export default function createReduxStore( key, options ) { selector.registry = registry; } const boundSelector = ( ...args ) => { + if ( + selector.normalizeArgs && + typeof selector.normalizeArgs === 'function' && + args?.length + ) { + args = selector.normalizeArgs( args ); + } const state = store.__unstableOriginalGetState(); return selector( state.root, ...args ); }; + // Expose normalization method on the bound selector + // in order that it can be called when fullfilling + // the resolver. + boundSelector.normalizeArgs = selector.normalizeArgs; + const resolver = resolvers[ selectorName ]; + if ( ! resolver ) { boundSelector.hasResolver = false; return boundSelector; @@ -604,8 +617,12 @@ function mapSelectorWithResolver( } const selectorResolver = ( ...args ) => { - if ( resolver.normalizeArgs && args?.length ) { - args = resolver.normalizeArgs( args ); + if ( + selector.normalizeArgs && + typeof selector.normalizeArgs === 'function' && + args?.length + ) { + args = selector.normalizeArgs( args ); } fulfillSelector( args ); return selector( ...args ); diff --git a/packages/data/src/redux-store/test/index.js b/packages/data/src/redux-store/test/index.js index 4c65f4822036d..9c06b6bff80c4 100644 --- a/packages/data/src/redux-store/test/index.js +++ b/packages/data/src/redux-store/test/index.js @@ -288,46 +288,52 @@ describe( 'resolveSelect', () => { } ); describe( 'normalizing args', () => { - it( 'should call the .normalizeArgs method on the resolver if it exists', async () => { + it( 'should call the normalizeArgs method of the selector for both the selector and the resolver', async () => { const registry = createRegistry(); - const resolver = () => {}; + const selector = () => {}; - resolver.normalizeArgs = jest.fn( ( ...args ) => args ); + const normalizingFunction = jest.fn( ( ...args ) => args ); + + selector.normalizeArgs = normalizingFunction; registry.registerStore( 'store', { reducer: () => {}, selectors: { - getItems: () => 'items', + getItems: selector, }, resolvers: { - getItems: resolver, + getItems: () => 'items', }, } ); registry.select( 'store' ).getItems( 'foo', 'bar' ); - expect( resolver.normalizeArgs ).toHaveBeenCalledWith( [ - 'foo', - 'bar', - ] ); + expect( normalizingFunction ).toHaveBeenCalledWith( [ 'foo', 'bar' ] ); + + // Needs to be call twice: + // 1. When the selector is called. + // 2. When the resolver is fullfilled. + expect( normalizingFunction ).toHaveBeenCalledTimes( 2 ); } ); - it( 'should not call normalizeArgs if there are no arguments passed to the resolver', async () => { + it( 'should not call the normalizeArgs method if there are no arguments passed to the selector (and thus the resolver)', async () => { const registry = createRegistry(); - const resolver = () => {}; + const selector = () => {}; - resolver.normalizeArgs = jest.fn( ( ...args ) => args ); + selector.normalizeArgs = jest.fn( ( ...args ) => args ); registry.registerStore( 'store', { reducer: () => {}, selectors: { - getItems: () => 'items', + getItems: selector, }, resolvers: { - getItems: resolver, + getItems: () => 'items', }, } ); + + // Called with no args so the normalizeArgs method should not be called. registry.select( 'store' ).getItems(); - expect( resolver.normalizeArgs ).not.toHaveBeenCalled(); + expect( selector.normalizeArgs ).not.toHaveBeenCalled(); } ); } );