Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test multiple sequential calls with Jasmine

I am trying to test a function that unsubscribes from all subscriptions:

ngOnDestroy() {
        this.tryUnsubscribe(this.carsSubscription);
        this.tryUnsubscribe(this.partsSubscription);
        this.tryUnsubscribe(this.shopsSubscription);
    }

This is the test I wrote for the function:

it('should unsubscribe from subscriptions ', () => { 
      spyOn(component, "tryUnsubscribe");     
      component.ngOnDestroy();
      expect(component.tryUnsubscribe).toHaveBeenCalledWith(component['carsSubscription']);
      expect(component.tryUnsubscribe).toHaveBeenCalledWith(component['partsSubscription']);
      expect(component.tryUnsubscribe).toHaveBeenCalledWith(component['shopsSubscription']);
    });

The problem:

If I comment out a function call, the tests still passes.

ngOnDestroy() {
        this.tryUnsubscribe(this.carsSubscription);
        //this.tryUnsubscribe(this.partsSubscription);
        this.tryUnsubscribe(this.shopsSubscription);
    }

Only if I comment out all of these function calls, the test fails:

ngOnDestroy() {
        //this.tryUnsubscribe(this.carsSubscription);
        //this.tryUnsubscribe(this.partsSubscription);
        //this.tryUnsubscribe(this.shopsSubscription);
    }

How to properly test this kind of function? What am I doing wrong?

like image 816
gfels Avatar asked Jan 29 '19 11:01

gfels


People also ask

How do I test API calls in Jasmine?

Create a Mock API with Jasminejson file in your root directory. If not, you can set it up with this command: npm init -y . Your test should pass! Try changing the value of a to false, and running it again to see what it looks like when a test fails.

How do you use spyOn in Jasmine?

Jasmine provides the spyOn() function for such purposes. spyOn() takes two parameters: the first parameter is the name of the object and the second parameter is the name of the method to be spied upon. It replaces the spied method with a stub, and does not actually execute the real method.

What is callFake Jasmine?

callFake(fn)Tell the spy to call a fake implementation when invoked.

What is test bed in Jasmine?

TestBed is a mock environment to run Angular2 component tests without the browser.


2 Answers

It is also possible to check all arguments at once using Jasmine calls.allArgs() method:

expect(spy.calls.allArgs()).toEqual([
  [component.carsSubscription],
  [component.partsSubscription],
  [component.shopsSubscription]
]);

Here is modified Fabian Küng's answer in stackblitz.

like image 28
Gennadii Saltyshchak Avatar answered Oct 06 '22 01:10

Gennadii Saltyshchak


I would rewrite your test to the following:

it('should unsubscribe from subscriptions ', () => { 
  const spy = spyOn(component, 'tryUnsubscribe');     
  component.ngOnDestroy();

  // Check how many times the spy was called
  expect(spy).toHaveBeenCalledTimes(3);
});

If you now uncomment one of the tryUnsubscribe calls, the test should fail as the spy was only called twice.

Another approach would be to mock the subscriptions or just set them to a dummy value to test that inside the ngDestroy tryUnsubscribe was called with those 3 component variables:

it('test unsubscribing', () => {
  // Mock values
  component.carsSubscription = Observable.of(1).subscribe(() => {});
  component.partsSubscription = Observable.of(1).subscribe(() => {});
  component.shopsSubscription = Observable.of(1).subscribe(() => {});

  const spy = spyOn(component, 'tryUnsubscribe').and.callThrough();     
  component.ngOnDestroy();

  // Check how many times the spy was called
  expect(spy).toHaveBeenCalledTimes(3);

  // Check arguments
  expect(spy.calls.all()[0].args[0]).toEqual(component.carsSubscription);
  expect(spy.calls.all()[1].args[0]).toEqual(component.partsSubscription);
  expect(spy.calls.all()[2].args[0]).toEqual(component.shopsSubscription);
});

Here is a working stackblitz with the test.

like image 117
Fabian Küng Avatar answered Oct 06 '22 00:10

Fabian Küng