Search code examples
angulartestingrxjsobservableangular-spectator

RxJs: Testing observable that depends on other observable/


I have an observable called isSearchEnabled$, that indicates whether the search button on search form is clickable or not. This is the code for the observable:

isSearchEnabled$ = anotherObject.errorSource$.pipe(map((errors) => errors.length === 0);

As one can see, this observable is depending on another observable, which emits an array every time form validation occurs. So isSearchEnabled emits a boolean true when the array is empty, false otherwise.

I wanna test this observable, but I'm not sure how. I should mock anotherObject.errorSource$ to emit fake errors, and check whether isSearchEnabled$ returns true or false?

How should i do it in Angular/RxJS? If somebody have solution in spectator, or just a regular solution, I'd really appreciate it!

PS.: I know I should provide a working example, but I think this description is quiet straightforward, and no need further code.


Solution

  • If anotherObject is an object as you specify above you could do something like this. AnotherObject Stackblitz

    describe("HelloComponent", () => {
      let spectator: Spectator<HelloComponent>;
    
      const createComponent = createComponentFactory({
        component: HelloComponent,
        providers: [],
        detectChanges: false
      });
    
      beforeEach(() => {
        spectator = createComponent();
      });
    
      it("should be disabled", done => {
        const errors = [new Error("xyz"), new Error("abc")];
        spectator.component.anotherObject = { errorSource$: of(errors) };
        spectator.detectChanges();
        spectator.component.isSearchEnabled$.subscribe({
          next: isSearchEnabled => {
            expect(isSearchEnabled).toBeFalse();
           //You might want to test here whether your component template/state changed..
            done();
          }
        });
      });
    
      it("should be enabled", done => {
        spectator.component.anotherObject = { errorSource$: of([]) };
        spectator.detectChanges();
        spectator.component.isSearchEnabled$.subscribe({
          next: isSearchEnabled => {
            expect(isSearchEnabled).toBeTrue();
            done();
          }
        });
      });
    });
    

    If you get the observable from the akita query the best option is to mock the query method your observable is dependent on. I haven't tested the code below, but something similar should work.

      let spectator: Spectator<HelloComponent>;
      let query: SpyObject<AkitaAnotherObjectQuery>;
    
      const createComponent = createComponentFactory({
        component: HelloComponent,
        mocks: [AkitaAnotherObjectQuery],
        detectChanges: false
      });
    
      beforeEach(() => {
        spectator = createComponent();
        query = spectator.inject(AkitaAnotherObjectQuery);
        //return empty array to check if search is enabled by default
        query.selectErrorSource.andReturn(of([]));
      });
    
      it('should be enabled', () => {
         spectator.detectChanges();
         //todo test whether component state changed..
      });
    
      //test could be fake async or if you want to test the observable you can subscribe to it in the test below
      it('should be disabled', () => {
        const errors = [new Error('myError')];
        query.selectErrorSource.andReturn(of(errors));
        spectator.detectChanges();
        //todo test whether component state changed..
       });
    
      ....
    
    

    Hope it works out, let me know if you have any more questions. If you want I can also add an example of the akita query mock in Stackblitz, just let me know.