Stewart
Stewart

Reputation: 1899

Why isn't my async Angular Jasmine unit test working?

I'm trying to test an asynchronous component method and I think I'm using the asynchronous testing capabilities of Angular 4 correctly, but it isn't working. My problem is that when I run the test, it doesn't wait for the Promise to resolve. It seems like the asynchronous nature of function is causing a timeout to be tripped and the test to be exited prematurely. The test will pass no matter what because all expect() statements inside whenStable() get skipped.

If I omit the async() wrapper function and switch to the Jasmine syntax of passing in a done callback and call it at the end of the whenStable() block, it works correctly. Can anyone tell me why it doesn't work with the Angular async() wrapper?

My code looks like this:

// my.component.ts
ngOnInit() {
  this.getResults().then((results) => {
    this.results = results;
  });
}

// My asynchronous function, which takes 1.5s to load results
getResults() {
  let promise = new Promise((resolve) => {
    setTimeout(() => {
      resolve('foo');
    }, 1500);
  })
  return promise;
}


// my.component.spec.ts (Angular async version which doesn't work)
it('should load results', async(() => {
  spyOn(component, 'getResults').and.returnValue(Promise.resolve('bar'));
  component.ngOnInit();

  fixture.whenStable().then(() => {
    // Everything in here gets skipped when I run the test
    fixture.detectChanges();
    // This should cause the test to fail, but it doesn't because it's not run in time
    expect(true).toBe(false)
  });
}));

// my.component.spec.ts (Jasmine version that works)
it('should load results', (done) => {
  spyOn(component, 'getResults').and.returnValue(Promise.resolve('bar'));
  component.ngOnInit();

  fixture.whenStable().then(() => {
    fixture.detectChanges();
    // This should fail and it does because the test works using Jasmine's "done" callback
    expect(true).toBe(false);
    done();
  });
});

Upvotes: 3

Views: 5049

Answers (2)

Florian Motteau
Florian Motteau

Reputation: 3724

I had some trouble dealing with this, we solved it by using the angular/testing async function in beforeEach :

beforeEach(async(() => { // <-- use async
    TestBed.configureTestingModule({
        declarations: [AppComponent],
    });

    fixture = TestBed.createComponent(AppComponent);

    component = fixture.componentInstance;

    // The following line is to blame! Removing it makes the test work correctly.
    fixture.detectChanges();
}));

... as the docs says : https://angular.io/guide/testing#async-test-with-async.

Upvotes: 0

Stewart
Stewart

Reputation: 1899

Thanks to @yurzui's Plunker, I determined that my problem was caused by my calling fixture.detectChanges() in my beforeEach() method:

beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [AppComponent],
    });

    fixture = TestBed.createComponent(AppComponent);

    component = fixture.componentInstance;

    // The following line is to blame! Removing it makes the test work correctly.
    fixture.detectChanges();
});

Upvotes: 4

Related Questions