Angular Unit Testing with RxJS, pipe, and subscribe

Viewed 2157

I'm trying to write some unit test (Jasmine) for my Angular 11 Component. In ngOnInit() it calls two http ajax functions from the service that return data from the database. Both return a Subscription (rxjs), and I chained them with pipe() and switchMap().

It's something like this:

ngOnInit(): void {
    const configID = 12345;
    this.service.getDataOne(configID)
        .pipe(
            switchMap(() => {
                return this.service.getDataTwo(configID);
            })
        )
        .subscribe(res => {
              if(res.SUCCESS) {
                    this.dataSource.data = res.DATA.RESULT;
              }
              else {
                  this.error = res.ERROR;
              }
         });
}

In my spec.ts:

describe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
const serviceSpy = jasmine.createSpyObj('MyService', [ 'getDataOne', 'getDataTwo' ]);
const mockSuccessData1 = {
    SUCCESS: true
    , DATA: 'mock result 1';
}

const mockSuccessData2 = {
    SUCCESS: true 
    , DATA: 'mock result 2';
}

beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
        declarations: [ MyComponent ]
        , imports: [ ]
        , providers : [
            { provide: MyService, useValue: serviceSpy }
        ]
    }).compileComponents();

    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    serviceSpy.getDataOne.and.returnValue(of(mockSuccessData1));

    fixture.detectChanges();
}));

it('should create', () => {
    expect(component).toBeTruthy();
});

});

What's the proper way to test this component and mock the subscriptions? I tried serviceSpy.getDataOne.and.returnValue(of(mockSuccessData1 )); But I got error "Failed: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable."

Thank you in advance.

1 Answers

I would recommend to create a mock service and then use it under providers as UseClass

Create a mock service like below:

export class MockMyService {

    getDataOne() {
        return of({
            SUCCESS: true,
            DATA: 'mock result 1'
        })
    }

    getDataTwo() {
        return of({
            SUCCESS: true
            , DATA: 'mock result 2'
        })


    }
}

and in your test file

beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
        declarations: [ MyComponent ]
        , imports: [ ]
        , providers : [
            { provide: MyService, useClass: MockMyService }
        ]
    }).compileComponents();

    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
}));

it('should create', () => {
    expect(component).toBeTruthy();
});

Related