Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jasmine waiting for async function inside the tested function

I'm trying to test an Angular 2 component which relies on a service call to populate the data. But, this service calls promise is handled inside another function.

this.data = null; //empty data is defined here.

public getDataMethod(){
    // controller related logic
    privateService.privateMethod(
        (data) => {this.data = data} //the data is populated here
    )
}

How can I wait for the inner function to resolve?

I read that we can wait for promises to resolve with 'done' but the only examples I found were of directly calling the promise. (Not a nested promise inside a function)

I tried passing the done method into the function and it works well.

public getDataMethod(done){
    // controller related logic
    privateService.privateMethod(
        (data) => {this.data = data} //the data is populated here
        done(); //Calling done when the promise is resolved. 
    )
}

But, that does muddy up the code that's tested. Is there a better way of waiting for the data value to populate before running the tests?

like image 486
nipuna777 Avatar asked Mar 23 '17 05:03

nipuna777


1 Answers

This is all explained in the Angular docs testing section Test a component with an async service. You basically have a couple options.

  1. Use async to wrap the tests. Angular knows when there are asynchronous tasks happening, because it uses zones to monkey patch all the asynchronous functions like setTimeout. When we use async, Angular will prevent the test from completing until all the async tasks are out of the queue.

     import { async } from '@angular/core/testing';
    
     it('..', async(() => {
        // any async calls that happen between here
        // will be completed before the test completes
     }))
    

    the other part to this is waiting for async tasks to complete before we make any assertions. For that, we can use fixture.whenStable() which will wait before the async tasks to complete, then notify us with a promise

     it('..', async(() => {
        service.someAsyncTask();
        fixture.whenStable().then(() => {
          expect(...) 
        })
     }))
    
  2. The other option is to use fakeAsync/tick combo. Angular allows us to wait for the async tasks to complete by calling tick. This allows us to make the test seem synchronous

     import { fakeAsync, tick } from '@angular/core/testing';
    
     it('..', fakeAsync(() => {
        service.someAsyncTask();
        tick();
        expect(...)
     }))
    
like image 128
Paul Samsotha Avatar answered Oct 17 '22 20:10

Paul Samsotha