Skip to content

Commit

Permalink
Data: Introduce countSelectorsByStatus redux metadata selector
Browse files Browse the repository at this point in the history
  • Loading branch information
tyxla committed Aug 17, 2023
1 parent e048534 commit a15e98e
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/data/src/redux-store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ function mapResolveSelectors( selectors, store ) {
getResolutionState,
getResolutionError,
hasResolvingSelectors,
countSelectorsByStatus,
...storeSelectors
} = selectors;

Expand Down
30 changes: 30 additions & 0 deletions packages/data/src/redux-store/metadata/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,33 @@ export function hasResolvingSelectors( state ) {
)
);
}

/**
* Retrieves the total number of selectors, grouped per status.
*
* @param {State} state Data state.
*
* @return {Object} Object, containing selector totals by status.
*/
export function countSelectorsByStatus( state ) {
const selectorsByStatus = {};

Object.values( state ).forEach( ( selectorState ) =>
/**
* This uses the internal `_map` property of `EquivalentKeyMap` for
* optimization purposes, since the `EquivalentKeyMap` implementation
* does not support a `.values()` implementation.
*
* @see https://github.com/aduth/equivalent-key-map
*/
Array.from( selectorState._map.values() ).forEach( ( resolution ) => {
const currentStatus = resolution[ 1 ]?.status ?? 'error';
if ( ! selectorsByStatus[ currentStatus ] ) {
selectorsByStatus[ currentStatus ] = 0;
}
selectorsByStatus[ currentStatus ]++;
} )
);

return selectorsByStatus;
}
63 changes: 63 additions & 0 deletions packages/data/src/redux-store/metadata/test/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,66 @@ describe( 'hasResolvingSelectors', () => {
expect( result ).toBe( true );
} );
} );

describe( 'countSelectorsByStatus', () => {
let registry;

beforeEach( () => {
registry = createRegistry();
registry.registerStore( 'store', {
reducer: ( state = null, action ) => {
if ( action.type === 'RECEIVE' ) {
return action.items;
}

return state;
},
selectors: {
getFoo: ( state ) => state,
getBar: ( state ) => state,
getBaz: ( state ) => state,
getFailingFoo: ( state ) => state,
getFailingBar: ( state ) => state,
},
resolvers: {
getFailingFoo: () => {
throw new Error( 'error fetching' );
},
getFailingBar: () => {
throw new Error( 'error fetching' );
},
},
} );
} );

it( 'counts selectors properly by status, excluding missing statuses', () => {
registry.dispatch( 'store' ).startResolution( 'getFoo', [] );
registry.dispatch( 'store' ).startResolution( 'getBar', [] );
registry.dispatch( 'store' ).startResolution( 'getBaz', [] );
registry.dispatch( 'store' ).finishResolution( 'getFoo', [] );
registry.dispatch( 'store' ).finishResolution( 'getBaz', [] );

const { countSelectorsByStatus } = registry.select( 'store' );
const result = countSelectorsByStatus();

expect( result ).toEqual( {
finished: 2,
resolving: 1,
} );
} );

it( 'counts errors properly', async () => {
registry.dispatch( 'store' ).startResolution( 'getFoo', [] );
await resolve( registry, 'getFailingFoo' );
await resolve( registry, 'getFailingBar' );
registry.dispatch( 'store' ).finishResolution( 'getFoo', [] );

const { countSelectorsByStatus } = registry.select( 'store' );
const result = countSelectorsByStatus();

expect( result ).toEqual( {
finished: 1,
error: 2,
} );
} );
} );

0 comments on commit a15e98e

Please sign in to comment.