Unit test 'success' and 'error' observable response in component for Angular 2

24,948

Solution 1

I would create two mocks - one that throws an error:

class ObserverThrowServiceStub {
    getData() {
        return Observable.throw(new Error('Test error'));
    }
}

and one that returns successfully.

class ObserverSuccessServiceStub {
    getData() {
        return Observable.from(data);
    }
}

Then, instead of providing the same mock service to all tests, you provide the failing/successful mock service appropriately depending on the test in question (obviously you'll need to move your module configuration into a configurable method that you call from within each test rather than in the .beforeEach() code.

There is a really nice article on testing Angular services using Observables here (which uses exactly this model): http://www.zackarychapple.guru/angular2/2016/11/25/angular2-testing-services.html

Solution 2

someObj.ObservableReturninFunction().subscribe(
    (obj)=> {
        conosle.log(obj.message);
    },
    (err)=>{
        console.log(err.message);
    }
});
when success;
    SpyOn(someObj,"ObservableReturninFunction").and.returnValue(
            Observable.of({message: "something"}));
when erro:
    SpyOn(someObj,"ObservableReturninFunction").and.returnValue(
        Observable.throw({message: "some-error"}));

Solution 3

You can use Jasmine Spy to spyOn your mock service class's method which returns an Observable. More detail is here: Jasmine - how to spyOn instance methods

Share:
24,948
bmd
Author by

bmd

Updated on June 30, 2021

Comments

  • bmd
    bmd about 3 years

    I'm writing a unit test for a component that makes a call to a service OnInit. If the response is a 'success' one action taken and another for an 'error'.

    What is the best way to test both cases? I've created a simplified version of the component and unit test. Something that I could easily test against in both cases.

    I've attempted to implement the solution here but I must be off on the implementation. I've also attempted to throw an error as you will see in the spec and comments.

    Component

    @Component({
      selector: 'app-observer-throw-unit-test',
      template: '<p>{{ data }}</p>'
    })
    export class ObserverThrowUnitTestComponent implements OnInit {
        public data: string;
    
        constructor(private _observerThrowService: ObserverThrowService) { }
    
        ngOnInit() {
            this._observerThrowService.getData().subscribe(
                (data) => {
                    this.data = data;
                },
                (error) => {
                    this.redirect()
                }
            )
        }
    
        redirect() {
            this.data = "Redirecting...";
        }
    
    }
    

    Spec

    const data: string = "Lorem ipsum dolor sit amet.";
    
    const ObserverThrowServiceStub = {
      error: false,
      getData() {
        return Observable.create((observer) => {
          if(this.error) {
            observer.error(new Error());
          } else {
            observer.next(data);
          }
          observer.complete();
        })
      }
    }
    
    describe('ObserverThrowUnitTestComponent', () => {
      let component: ObserverThrowUnitTestComponent;
      let fixture: ComponentFixture<ObserverThrowUnitTestComponent>;
      let _observerThrowService: ObserverThrowService;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [ ObserverThrowUnitTestComponent ],
          providers: [
            { provide: ObserverThrowService, useValue: ObserverThrowServiceStub },
          ]
        })
        .compileComponents();
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(ObserverThrowUnitTestComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
        _observerThrowService = TestBed.get(ObserverThrowService);
      });
    
      it('should set "data" to "Lorem ipsum dolor sit amet." on success', () => {
          expect(component.data).toEqual("Lorem ipsum dolor sit amet.");
      });
    
      it('should set "data" on "Redirecting..." on error',() => {
        ObserverThrowServiceStub.error = true;
        // spyOn(_observerThrowService, "getData").and.returnValue(Observable.throw("error")); // This did not work and returned : TypeError: undefined is not a constructor (evaluating 'Observable_1.Observable.throw("error")') in src/test.ts
        spyOn(_observerThrowService, "getData")
        expect(component.data).toEqual("Redirecting...");
      });
    
      it('should set "data" on "Redirecting..." on error',() => {
        // This works after setting error to true in the previous test
        spyOn(_observerThrowService, "getData")
        expect(component.data).toEqual("Redirecting...");
      });
    
    });