Description
Following the description in the docs @ngrx/entity, I wrote a factory selector that uses selectAll and selectEntities provided by EntityAdapter:
export const selectEntityWithBuiltinSelectors = (userInput: string) =>
createSelector(selectMyFeatureState, (state): MyEntity | undefined => {
const id = Number(userInput);
const nameToLowerCase = userInput.toLowerCase();
return isNaN(id)
? selectAll(state).find(
(entity) => entity.name.toLowerCase() === nameToLowerCase,
)
: selectEntities(state)[id];
});
In the running application this works as expected.
However, writing a unit test
beforeEach(() => {
mockEntity = { id: 5, name: 'foo' };
featureState = {
entities: { [mockEntity.id]: mockEntity },
ids: [mockEntity.id],
isLoading: false,
searchResult: null,
errorMessage: '',
};
});
it('should at least reach the expect case', () => {
const result = selectEntityWithBuiltinSelectors(
mockEntity.name,
).projector(featureState);
expect(result).toBe(result);
});
fails at the point where I use projector with the following error message:
TypeError: Cannot read properties of undefined (reading 'ids')
It doesn't even reach the expect case.
Going through the debugger in WebStorm shows, that the argument state from the factory selector is actually set to the feature State Object and does have a property ids - although its array is empty. Still, that doesn't fit with the error message, that it cannot read a property of undefined.
Example code
I have reproduced the scenario here on stackblitz.
What i have tried
If I don't use the selectAll and selectEntities functions, but just the state object getters, the test succeeds:
export const selectEntityWithWorkaround = (userInput: string) =>
createSelector(selectMyFeatureState, (state): MyEntity | undefined => {
const id = Number(userInput);
const nameToLowerCase = userInput.toLowerCase();
return isNaN(id)
? Object.values(state.entities).find(
(entity: MyEntity | undefined) =>
entity?.name.toLowerCase() === nameToLowerCase,
)
: state.entities[id];
});
Although this is a workaround for the problem, it would render the adapter's selectors useless.
Unfortunately I couldn't find an example in the docs or on google that shows a test of a factory selector using selectAll and selectEntities of @ngrx/entity.
I believe this question might be related, but I can't see that its answers are helping in my case.
Summary
- How do I mock my state so that I can test this kind of selector?
- Do I need to use
provideMockStore()- and if so, how and why (since selectors should be pure functions)? - Can I use
projectorat all in this scenario or is there another way to test a selector?