You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Which @ngrx/* package(s) are the source of the bug?
store
Minimal reproduction of the bug/regression with instructions
When using createSelector to create memoized selector factories with NgRx's MockStore, the memoization appears to break when multiple selectors are created from the same factory with different parameters.
I like to create memoized selector factories using createSelector. However, it seems to not be working as expected.
This works:
import{getRouterSelectors}from'@ngrx/router-store';import{createSelector,Store}from'@ngrx/store';import{inject,Injectable}from'@angular/core';import{TestBed}from'@angular/core/testing';import{MockStore,provideMockStore}from'@ngrx/store/testing';constselectSomething=(text: string)=>createSelector((state: any)=>state,state=>state[text]);// Define a selector factoryexportconstselectByText=createSelector((text: string)=>text,text=>createSelector(selectSomething(text),something=>something+'more'));// In service:
@Injectable()classCurrentService{
#store =inject(Store);readonlysomething$=this.#store.select(selectByText('param1'));}// In test:describe('CurrentService',()=>{letmockStore: MockStore;letservice: CurrentService;beforeEach(()=>{TestBed.configureTestingModule({providers: [CurrentService,provideMockStore()],});mockStore=TestBed.inject(MockStore);service=TestBed.inject(CurrentService);});it('should handle overridden selectors',done=>{mockStore.overrideSelector(selectByText('param1'),'value1');expect(mockStore.selectSignal(selectByText('param1'))()).toBe('value1');service.something$.subscribe(val=>{expect(val).toBe('value1');done();});});});
But weird behaviors happen when reusing the selector factory when it ostensibly shouldn't:
import{getRouterSelectors}from'@ngrx/router-store';import{createSelector,Store}from'@ngrx/store';import{inject,Injectable}from'@angular/core';import{TestBed}from'@angular/core/testing';import{MockStore,provideMockStore}from'@ngrx/store/testing';constselectSomething=(text: string)=>createSelector((state: any)=>state,state=>state[text]);// Define a selector factoryexportconstselectByText=createSelector((text: string)=>text,text=>createSelector(selectSomething(text),something=>something+'more'));// In service:
@Injectable()classCurrentService{
#store =inject(Store);readonlysomething$=this.#store.select(selectByText('param1'));readonlyelse$=this.#store.select(selectByText('param2'));}// In test:describe('CurrentService',()=>{letmockStore: MockStore;letservice: CurrentService;beforeEach(()=>{TestBed.configureTestingModule({providers: [CurrentService,provideMockStore()],});mockStore=TestBed.inject(MockStore);service=TestBed.inject(CurrentService);});it('should handle overridden selectors',done=>{mockStore.overrideSelector(selectByText('param1'),'value1');expect(mockStore.selectSignal(selectByText('param1'))()).toBe('value1');service.something$.subscribe(val=>{// This breaks and returns "undefinedmore"expect(val).toBe('value1');done();});});});
import{getRouterSelectors}from'@ngrx/router-store';import{createSelector,Store}from'@ngrx/store';import{inject,Injectable}from'@angular/core';import{TestBed}from'@angular/core/testing';import{MockStore,provideMockStore}from'@ngrx/store/testing';constselectSomething=(text: string)=>createSelector((state: any)=>state,state=>state[text]);// Define a selector factoryexportconstselectByText=createSelector((text: string)=>text,text=>createSelector(selectSomething(text),something=>something+'more'));// In service:
@Injectable()classCurrentService{
#store =inject(Store);readonlysomething$=this.#store.select(selectByText('param1'));readonlyelse$=this.#store.select(selectByText('param2'));}// In test:describe('CurrentService',()=>{letmockStore: MockStore;letservice: CurrentService;beforeEach(()=>{TestBed.configureTestingModule({providers: [CurrentService,provideMockStore()],});mockStore=TestBed.inject(MockStore);service=TestBed.inject(CurrentService);});it('should handle overridden selectors',done=>{mockStore.overrideSelector(selectByText('param1'),'value1');mockStore.overrideSelector(selectByText('param2'),'value2');// This worksexpect(mockStore.selectSignal(selectByText('param2'))()).toBe('value2');// This breaks and returns "undefinedmore"expect(mockStore.selectSignal(selectByText('param1'))()).toBe('value1');service.something$.subscribe(val=>{expect(val).toBe('value1');done();});});});
I used Object.assign(selector, { random: Math.random() } in my factory to verify that createSelector is producing memoized selectors as expected. But somehow, with mock store, it's managing to break memoization.
Expected behavior
The selectors (used as selector factories) in the example should be memoized and return the expected results.
Versions of NgRx, Angular, Node, affected browser(s) and operating system(s)
I would be willing to submit a PR to fix this issue
Yes
No
The text was updated successfully, but these errors were encountered:
davidmccoy-8451
changed the title
Bug: MockStore fails to properly handle overrides with memoized selector factories in store.select()
Bug: MockStore fails to properly handle overrides with memoized selector factories in store.selectSignal()
Jan 27, 2025
Which @ngrx/* package(s) are the source of the bug?
store
Minimal reproduction of the bug/regression with instructions
When using
createSelector
to create memoized selector factories with NgRx's MockStore, the memoization appears to break when multiple selectors are created from the same factory with different parameters.I like to create memoized selector factories using
createSelector
. However, it seems to not be working as expected.This works:
But weird behaviors happen when reusing the selector factory when it ostensibly shouldn't:
I used
Object.assign(selector, { random: Math.random() }
in my factory to verify thatcreateSelector
is producing memoized selectors as expected. But somehow, with mock store, it's managing to break memoization.Expected behavior
The selectors (used as selector factories) in the example should be memoized and return the expected results.
Versions of NgRx, Angular, Node, affected browser(s) and operating system(s)
NgRx: 16.1.0
Angular: 16.2.11
Node: 20.18.1
Browser: N/A
OS: macOS
Other information
No response
I would be willing to submit a PR to fix this issue
The text was updated successfully, but these errors were encountered: