Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest: mock RxJs pipe

How to mock more complex RxJs behavior (in a context of NgRx)?

Given a simple component (SomeComponent):

export class SomeComponent implements OnInit {
  foo$: Observable<any>;
  bar$: Observable<any>;

  constructor(private store: Store<State>) {}

  ngOnInit() {
    this.foo$ = this.store.pipe(select(getFooSelector));
    this.bar$ = this.store.pipe(select(getBarSelector));
  }
}

I would like to mock store in a way that:

  • Based on a passed selector the mock store returns a different value.
  • Spy what argument (selector) was passed to the select operator.

Based on a passed selector the mock store returns different value

I would see it as something like that:

store.pipe = jest.fn(selectOperator => {
  switch (selectOperator.arguments[0]) {
    case getFooSelector:
      return foo;
    case getBarSelector:
      return bar;
  }
}

Spy what argument (selector) was passed to select operator.

Something along those lines:

const spy = jest.spyOn(store, 'pipe');
expect(spy.mock.calls[0]).toHaveBeenCalledWith(select(getFooSelector));
expect(spy.mock.calls[1]).toHaveBeenCalledWith(select(getBarSelector));

Summary

I know both of those examples are pseudo codes but I hope they demonstrate what I am trying to achieve. If my approach is completely wrong that please do comment on that.

like image 707
Bielik Avatar asked Sep 27 '18 08:09

Bielik


2 Answers

Use RxJs Marbles for testing RxJs with NgRx.

For more information read RxJS Marble Testing: RTFM and look Jest Testing - Jesse Sanders, Reactive Testing Strategies with NgRx - Brandon Roberts & Mike Ryan

For implementation use jest.fn().mockImplementationOnce

store.pipe = jest.fn()
   .mockImplementationOnce(foo)
   .mockImplementationOnce(bar)

expect(store.pipe).toHaveBeenCalledWith(select(getFooSelector));
expect(store.pipe).toHaveBeenCalledWith(select(getBarSelector));
like image 142
Kliment Ru Avatar answered Nov 16 '22 01:11

Kliment Ru


With NGRX v8.6.0 you should be able to do something like this:

let fixture: ComponentFixture<SomeComponent>;
let mockStore: MockStore<State>;

beforeEach(() => {
    TestBed.configureTestingModule({
        providers: [provideMockStore()],
        declarations: [SomeComponent],
    });

    fixture = TestBed.createComponent(SomeComponent);
    mockStore = TestBed.get(Store);
    fixture.detectChanges();
});

it('should have a value of foo', done => {
    mockStore.overrideSelector(getFooSelector, 'foo');

    foo$.subscribe(res => {
        done();
        expect(res).toBe('foo');
    });
});

it('should have a value of bar', done => {
    mockStore.overrideSelector(getBarSelector, 'bar');

    bar$.subscribe(res => {
        done();
        expect(res).toBe('bar');
    });
});

https://ngrx.io/guide/store/testing

like image 34
Ramon Schmitt Avatar answered Nov 16 '22 01:11

Ramon Schmitt