How to test ngrx pipe select in Rxjs 6

Viewed 8256

Previously I could test the below store select

this.store.select(fromRoot.someselector).pipe(map(r => this.store.dispatch(new Action())));

This was in my test

{provide: Store, useValue: jasmine.createSpyObj('store', ['select']);

store.select.and.returnValue(of({}));

But now it has changed to pipes

this.store.pipe(select(fromRoot.someselector));

this.store.pipe(
        select(fromRoot.someselector), 
        filter(result => !!result), 
        map(r => { 
             if (result === ' hello') { 
               this.store.dispatch(new Action()); 
             } 
           }
        ));

How to test this especially when you have map after select and within it you are dispatching an action and you want verify action was called.

2 Answers

Skip the operators and test directly the result of the stream:

store
  .pipe(select('selector'))
  .subscribe(val => expect(val).toBe(theMockedValSentToTheSpy))

To explain further:

  • create a mock of your store
  • create a mock of your value
  • return this mocked value in your mocked store
  • expect your component variable to return the mocked value

This gives:

const mockedValue = { id: 1 };
const storeSubjectMock = new BehaviorSubject(mockedValue);
const mockedStore = {
  pipe: () => storeSubjectMock.asObservable(),
};

// { provide: Store, useValue: mockedStore }; in your testbed

it('should return an unaltered value', () => {
  component.variableReferencingStore
    .pipe(select('selector'))
    .subscribe(val => expect(val).toBe(mockedValue))
});

Now the good thing about that is that you can test all operators like that. Say your component variable is

storeValue$ = this.store.pipe(
  select('selector'),
  map(value => ({ ...value, name: 'customName' }))
)

Then your tests just changes to:

it('should return an altered value with a name property set to customName', () => {
  component.variableReferencingStore
    .pipe(select('selector'))
    .subscribe(val => expect(val).toEqual({ ...mockedValue, name: 'customName'))
});

spyOn(store, 'pipe').and.callFake(selector => { return of(true); });
... expect(store.pipe).toHaveBeenCalledTimes(1); // pass

Related