Services

Last updated 6 months ago

When we have a service without dependencies we can just instantiate it without using Spectator. For example:

describe("AuthService", () => {
it("should ...", () => {
const authService = new AuthService();
expect(authService.isLoggedIn()).toBeTruthy();
});
});

If you want to use Spectator with the above example, you can do the following:

describe("AuthService", () => {
const spectator = createService<AuthService>(AuthService);
it("should ...", () => {
expect(spectator.service.isLoggedIn()).toBeTruthy();
});
});

When testing a service it’s often the case that we want to mock other services in its DI, as we focus on the service being tested. For example:

@Injectable()
export class DateService {
isExpired(time) {
// ...
}
}
@Injectable()
export class AuthService {
constructor( private dateService: DateService ) {
}
isLoggedIn() {
if( this.dateService.isExpired('timestamp') ) {
return false;
}
return true;
}
}

The following example shows how to test the AuthService with Spectator.

import { createService } from "@netbasal/spectator";
describe("AuthService", () => {
const spectator = createService({
service: AuthService,
mocks: [DateService]
});
it("should not be logged in", () => {
let dateService = spectator.get<DateService>(DateService);
dateService.isExpired.and.returnValue(true);
expect(spectator.service.isLoggedIn()).toBeFalsy();
});
it("should be logged in", () => {
let dateService = spectator.get<DateService>(DateService);
dateService.isExpired.and.returnValue(false);
expect(spectator.service.isLoggedIn()).toBeTruthy();
});
});

Every service that you pass to the mocks property will be called with the mockProvider() function.

The mockProvider() function converts each service method to a jasmine spy. (i.e jasmine.createSpy()).

Here are some of the methods it exposes:

dateService.isExpired.and.callThrough();
dateService.isExpired.and.callFake(() => fake);
dateService.isExpired.and.throwError('Error');
dateService.isExpired.andCallFake(() => fake);

The createService() function returns a plain object with the following properties:

  • service - Get an instance of the service

  • get<T> - A proxy for Angular TestBed.get()

If you want to use the actual providers you can still pass the providers key. For example:

const spectator = createService({
service: AuthService,
providers: [DateService]
});
it("should be logged in", () => {
expect(spectator.service.isLoggedIn()).toBeTruthy();
});

Note: You will still get an autocomplete for these services as spy objects (we're working to solve that).

Typed Mocks

You can use the mockProvider() function with any test, for example:

import { SpyObject, mockProvider } from '@netbasal/spectator';
let otherService: SpyObject<OtherService>;
let service: TestedService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
TestedService,
mockProvider(OtherService)
],
});
otherService = TestBed.get(OtherService);
service = TestBed.get(GoogleBooksService);
});
it('should be 0', () => {
otherService.method.andReturn('mocked value'); // mock is strongly typed
// then test serivce
});