I was reproducing some examples of the Angular documentation to improve my understanding of angular unit tests, and I ended up in a simple test case when I can't figure out what's going on.
Here is my app.component.ts file when I have a single method "getQuote" that get a quote from a service.
@Component({...})
export class AppComponent {
errMsg: string;
quote: Observable<string>;
constructor (private twainService: TwainService) {}
getQuote () {
this.quote = this.twainService.getQuote().pipe(
catchError(err => {
this.errMsg = err;
return of('...');
})
);
}
}
Then, I created a test to verify if my errMsg prop was correctly updated in case I got an error from my twainService.getQuote method :
describe('AppComponent', () => {
let fixture: ComponentFixture<AppComponent>;
let component: AppComponent;
let getQuoteSpy;
beforeEach(async(() => {
const twainService = jasmine.createSpyObj('TwainService', ['getQuote']);
getQuoteSpy = twainService.getQuote.and.returnValue(of(testQuote));
TestBed.configureTestingModule({
declarations: [
AppComponent
],
providers: [
{ provide: TwainService, useValue: twainService }
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AppComponent);
component = fixture.debugElement.componentInstance;
});
it('should get error msg when TwainService fails', async(async () => {
const errMsg = 'TwainService fails';
getQuoteSpy.and.returnValue(throwError(errMsg));
component.getQuote();
await fixture.whenStable();
expect(component.errMsg).toBe(errMsg);
}));
});
But here is the problem : this test always fails, and I can't get to see what's wrong.
Playing around, I managed to find that adding a "fixture.detectChanges()" like the following was making the test works, but I don't understand why. I thought the detectChanges method was only used to propagate changes to the component view.
it('should get error msg when TwainService fails', async(async () => {
const errMsg = 'TwainService fails';
getQuoteSpy.and.returnValue(throwError(errMsg));
component.getQuote();
fixture.detectChanges();
await fixture.whenStable();
expect(component.errMsg).toBe(errMsg);
}));
I tested with async, fakeAsync, and using synchronous observable emitting directly an error and asynchronous observable, and the result is always the same.
If anyone can help me understand what's going on there :)