It’s about Angular 2+ Unit Test.

Angular: v7.2.3

Karma: v4.0.1

Jasmine-core: v3.1.0

Add the component

beforeEach(async(() => {

TestBed.configureTestingModule({

declarations: [

AppComponent

],

}).compileComponents();

}));

// compileComponents may not needed if using WebPack

Create a component

const fixture = TestBed.createComponent(AppComponent);

const app = fixture.debugElement.componentInstance;

Override entryComponents

TestBed.overrideModule(BrowserDynamicTestingModule, {

set: {

entryComponents: [SomeComponent]

}

});

Create compiled HTML component

const fixture = TestBed.createComponent(AppComponent);

fixture.detectChanges();

const compiled = fixture.debugElement.nativeElement;

compiled.querySelector('h1').textContent

Inject Service to Component

const quoteService = fixture.debugElement.injector.get(QuoteService); fixture.detectChanges();

Mock Service

const data: Sample = new Sample('test');

class MockSampleService {

// Override test function from SampleService

test(): Observable<Sample>{

return of(data);

}

} providers: [{provide: SampleService, useValue: {}] TestBed.overrideProvider(SampleService, {useValue: new MockSampleService()});

Example of mocking HttpClient service

I usually use this fake HttpClient call to avoid “Cannot make XHRs from within a fake async test” Error.

const httpClientSpy: jasmine.SpyObj<HttpClient> = jasmine.createSpyObj('httpClient', ['get']); httpClientSpy.get.and.returnValue(of('your-data'})); ... providers: [{provide: HttpClient, useValue: {}] TestBed.overrideProvider(HttpClient, { useValue: httpClientSpy });

Spy On Service functions

spyOn(SomeService.prototype, 'someFunc').and.returnValue('test');

// commands to be run

expect(SomeService.prototype.someFunc).toHaveBeenCalled()

You don’t have to add returnValue function when spying on function.

Mock Component



template: `<app-user [user]="user"></app-user>`

})

class MockUser {

user = {

name: 'foobar'

};

} @Component ({template: ` `})class MockUser {user = {name: 'foobar'};

Mock Async (fakeAsync)

If I have an async call from constructor or ngOnInit, I’ll use fakeAsync in order to wait for all the call to be finished.

beforeEach(fakeAsync(() => {

fixture = TestBed.createComponent(AppComponent);

component = fixture.debugElement.componentInstance; component.ngOnInit();

tick();

...

}));

Troubleshooting

Error: 1 timer(s) still in the queue.

If you are using fakeAsync, please add tick() function, and try to increase the timer in tick function to test if it works (e.g tick(15000) ~ 15s)

TypeError: Cannot read property ‘getComponentFromError’ of null

Please add these reset your test environment in beforeEach function

TestBed.resetTestEnvironment();

TestBed.initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());

If you want to run a single test, you should import zone files. Then remove them when you run to run every test cases, otherwise, you will get some errors.

import 'zone.js/dist/zone';

import 'zone.js/dist/long-stack-trace-zone';

import 'zone.js/dist/proxy';

import 'zone.js/dist/sync-test';

import 'zone.js/dist/jasmine-patch';

import 'zone.js/dist/async-test';

import 'zone.js/dist/fake-async-test';

This is the command for running one test only.

ng test --main path-to-spec.file.js