JoshuaTree
JoshuaTree

Reputation: 1261

NgRX provideMockStore createSelector state undefined

When using the provide mockStore, my feature/selector functions only see state as undefined.

Due to this, I am only able to mock the selectors and cannot therefore perform a more fully integrated test.

Are selectors not supposed to see state when it's provided by the mock store or should this work?

Creating the mock store

     TestBed.configureTestingModule({
        providers: [
            AuthGuardGuard,
            provideMockStore({
                initialState: { ...initialState },
            }),
        ],
    });

Then logging the state that the selector should see, which is undefined.

export const currentUser = createSelector(
    authRootFeature,
    (state: fromAuthRoot.State) => {
        console.log(state); // Undefined
        return state.auth.currentUser;
    }
);

Upvotes: 2

Views: 4076

Answers (1)

Yair Cohen
Yair Cohen

Reputation: 2258

MockStore should be setting the state, I'll share with you two implementations that work and you can choose which one you prefer, there's missing info in your question so it's hard to point out why this is not working for you.

Here's one:

My selector:

export const selectFeature = createFeatureSelector<State, FeatureState>('feature');

export const getFeatureProperty = createSelector(
  selectFeature,
  (state) => state.featureProperty
);

My test file:

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;
  let mockStore: MockStore<State>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [LogsMenuViewComponent, LogsMenuViewDropdownComponent],
      providers: [provideMockStore({ initialState: { feature: { featureProperty: 123 } } as State })],
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MyComponent);
    mockStore = TestBed.inject(Store) as MockStore<State>;
    component = fixture.componentInstance;
    fixture.detectChanges();
  });
});

The reason this works is because my selector uses a feature, selector, so it's able to get the state properly.

Another implementation that might work for you is to override the selector, like this:

  describe('selectors', () => {
    let mockShowsSelector;
    beforeEach(() => {
      mockShowsSelector = store.overrideSelector(selectFavoriteShows, [{
        id: 3,
        name: 'C',
        description: 'Show C',
        imgUrl: '',
        isFavorite: true
      }]);
      fixture.detectChanges();
    });

    it('should render all favorite shows', () => {
      expect(fixture.debugElement.queryAll(By.css('.mat-card')).length).toBe(1);
    });

    it('should update the UI when the selector changes', () => {
      mockShowsSelector.setResult([ // overide selector
        {
          id: 1,
          name: 'A',
          description: 'Show A',
          imgUrl: '',
          isFavorite: true
        },
        {
          id: 2,
          name: 'B',
          description: 'Show B',
          imgUrl: '',
          isFavorite: true
        }
      ]);
      store.refreshState();
      fixture.detectChanges();
      expect(fixture.debugElement.queryAll(By.css('.mat-card')).length).toBe(2);
    });
  })

Upvotes: 6

Related Questions