7

I want to unit test and get coverage for all code but i am not able to get coverage for code present inside subscribe I am able to spy service and function but inside subscribe i am not able to unit test and get code coverage . following is Angular 7 code .

LoadListData(type) {
    this.itemListEnvName = [];
    if (type === 'EnvirnmentList') {
      this.environmentBookingService.getBookedEnv()
        .subscribe(
          (environmentBookingsData: EbEnvironmentBooking[]) => {
            if (environmentBookingsData.length > 0) {
              this.itemListEnvNameList = environmentBookingsData;
              this.itemListEnvName = [];
              this.itemListEnvNameList.forEach(element => {
                const obj = {};
                obj['id'] = element['environmentId'];
                obj['itemName'] = element['environmentName'];
                this.itemListEnvName.push(obj);
                this.generateCheckDisable = false;
              });
            } else {
              this.generateCheckDisable = true;
            }
          },
          (error) => {
            this.showMessage('No Response From Delivery DB API');
          }
        );
    } else {

      this.showMessage('No Response From Delivery DB API');
    }


  }

and code inside unit test case is like

 it('should call getBookedEnv service ', function () {
    const service = TestBed.get(EnvironmentBookingService); // get your service
    spyOn(service, 'getBookedEnv').and.callThrough(); // create spy
    component.LoadListData('EnvirnmentList');
    expect(service.getBookedEnv).toHaveBeenCalledWith();

  });

How to unit test code inside subscribe i.e.

if (environmentBookingsData.length > 0) {
              this.itemListEnvNameList = environmentBookingsData;
              this.itemListEnvName = [];
              this.itemListEnvNameList.forEach(element => {
                const obj = {};
                obj['id'] = element['environmentId'];
                obj['itemName'] = element['environmentName'];
                this.itemListEnvName.push(obj);
                this.generateCheckDisable = false;
              });
            } else {
              this.generateCheckDisable = true;
            }
Roshni joshi
  • 88
  • 1
  • 2
  • 7
  • Well, make sure that the service indeed returns an array that is not empty. You typically do that by actually mocking the service and make it return what you want instead of using the actual implementation of the service. – JB Nizet Apr 25 '19 at 06:00
  • getting response as array . can u give me some code example ?? – Roshni joshi Apr 25 '19 at 06:46
  • `spyOn(service, 'getBookedEnv').and.returnValue(of(theArrayForWhichYouWouldLikeToTestYourSuscribeCallback));` – JB Nizet Apr 25 '19 at 06:48

2 Answers2

3

If you want to test the code inside subscribe, you would have to mock your service call and then test the component variables that you are modifying inside subscribe, e.g. this.itemListEnvName and this.generateCheckDisable.

This could look like this:

 it('should call getBookedEnv service ', function () {
    const service = TestBed.get(EnvironmentBookingService); // get your service
    spyOn(service, 'getBookedEnv').and.callFake(() => {
      return of([]); // or return a list of bookings in case you want to test the first part of the if statement 
    });
    component.LoadListData('EnvironmentList');
    expect(service.getBookedEnv).toHaveBeenCalledWith();

    // additional tests that verify the inside of the subscribe (change below in case the mocked service returned something)
    expect(component.itemListEnvName).equalTo([]);
    expect(component.generateCheckDisable).equalTo(false);
  });
Fabian Küng
  • 5,925
  • 28
  • 40
0

You need to mock the service and have it return an Observable. I have put together a simple example in a StackBlitz to show one way to approach this with your code.

Things to note in the StackBlitz:

  • I mock the service with a spyObject, so there is no need to spy on the service later.
  • In this spyObject I set the return value of the internal function getBookedEnv() to be an Observable - this allows the code within the subscribe to be executed.
  • For any real testing you should replace the empty object currently returned by the getBookedEnv() to some reasonably mocked data.
  • note the providers array and where I replaced the service with the spy object.

Here is the describe from that StackBlitz:

describe('BannerComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;
  const envBookingServiceSpy = jasmine.createSpyObj('EnvironmentBookingService', {
    getBookedEnv: of({/* mock environmentBookingsData here */})
  });


  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ MyComponent ],
      providers: [
        { provide: EnvironmentBookingService, useValue: envBookingServiceSpy },
      ]
    })
    .compileComponents();
  }));

  beforeEach(async(() => {
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
  }));

  it('should call getBookedEnv service ', function () {
    const service = TestBed.get(EnvironmentBookingService); // get your service
    // spyOn(service, 'getBookedEnv').and.callThrough(); // create spy
    component.LoadListData('EnvirnmentList');
    expect(service.getBookedEnv).toHaveBeenCalledWith();
  });
});

I hope this helps give you an idea of how to start testing inside the subscribe of your method.

dmcgrandle
  • 5,934
  • 1
  • 19
  • 38
  • 1
    Thank you dmcgrandle, But considering this.environmentBookingService.getBookedEnv('data') has some parameter passed in it, how would above answer change? – Darshan theerth Jun 05 '20 at 07:11
  • 1
    @Darshantheerth - Not sure I fully understand your question as the OP's original example clearly did not have a parameter passed to that method. But theoretically if `getBookedEnv()` had a parameter passed, I would assume it is still expected to return an Observable so the example I gave would not change. If you are asking to test the parameter passed into the service method, that probably should be done in the service test, not here in the component test (though you could do it here). I suggest you ask a new question with all the details and get help that way if you're still confused. :) – dmcgrandle Jun 06 '20 at 20:03
  • thank you for your inputs. The code above works fine. – Darshan theerth Jun 08 '20 at 08:41
  • this shows how to test that the function gets called, but not what the op asked, how to test inside the subscribe... – bokkie Sep 07 '22 at 09:29