While I understand that the ideal way to test code is to consume it the same way it will be in production and thus don't directly deal with private properties and methods TypeScript has me a little flummoxed.
I have a user service.
// user.service.ts
import {Injectable} from '@angular/core';
import {AppHttpService} from '../app-http/app-http.service'
@Injectable()
export class UserService {
constructor(private appHttp: AppHttpService) {
}
}
As shown it depends on an appHttp service which has private properties and methods and let's say looks like this:
// app-http.service.ts
@Injectable()
export class AppHttpService {
private apiUrl = 'my domain';
constructor(private http: Http, private authHttp: AuthHttp) {
}
post(body): Observable<any> {
return this.http.post(this.apiUrl, body)
.map((res)=>res)
.catch((err)=>null);
}
}
In order to run an isolated test on my user service I would like to hand it a simple mock of my appHttp service. Unfortunately, if I just mock the public methods, properties of appHttp and provide it to my constructor like so:
// user.service.spec.ts
describe('', () => {
let appHttpMock = {
post: jasmine.createSpy('post')
};
let service = new UserService(appHttpMock);
beforeEach(() => {
})
it('', () => {
})
})
I get an error stating:
Error:(11, 33) TS2345:Argument of type '{ post: Spy; }' is not assignable to parameter of type 'AppHttpService'. Property 'apiUrl' is missing in type '{ post: Spy; }'.
If I change my mock to simply add the property I'll get another error complaining that it's not private. If I create a bonafide mock class such as:
// app-http.mock.ts
export class AppHttpMockService {
private apiUrl = 'my domain';
constructor() {
}
post() {
}
}
I'll still get another TypeScript error:
Error:(8, 33) TS2345:Argument of type 'AppHttpMockService' is not assignable to parameter of type 'AppHttpService'. Types have separate declarations of a private property 'apiUrl'.
What is a clean way to run isolated tests (i.e., one that doesn't require the time consuming creation of a testbed) without TypeScript fussing over the private properties and methods of the mock?
TestbedandconfigureTestingModule. angular.io/docs/ts/latest/guide/testing.html#!#testbedappHttpMockasany, to force TypeScript to relax the type check. AFAIK, you can also use jasmine.createSpyObj() to create the whole mock object, and pretend that the result is an AppHttpMockService:let appHttpMock = jasmine.createSpyObj(...) as AppHttpService;.jasmine.createSpyObj<AppHttpService>(...)