Unit Tests - server-specific services
Last but not least of your unit tests, should be to verify the server-specific services. In this lesson you will learn how to enforce Karma to run tests against code that includes server-specific objects and libraries.
Testing Server-Specific Classes#
You're moving to a more sophisticated part of unit testing in your Angular Universal application. In this lesson, you will create more advanced stubs that you need to perform assertions.
Stubbing MongoDB and TransferState#
Start by installing Sinon.JS that you will use to create stubs:
npm i -D sinon
Create a new file, src/app/products-server.service.spec.ts, then add import statements and set up variables that will hold stubs:
import { TestBed } from '@angular/core/testing';
import { ProductsServerService } from './products-server.service';
import { TransferState } from '@angular/platform-browser';
import { ObjectId } from 'mongodb';
import * as sinon from 'sinon';
describe('Products Server Service', () => {
let service: ProductsServerService;
let transferStateStub;
let dbClientStub;
let products = [
{
_id: ObjectId('5ed3bbefaf1c4c0e81d9b400'),
name: 'product1',
price: 2.4,
description: 'Lorem ipsum.',
image: 'juice',
},
{
_id: ObjectId('5ed3bbefaf1c4c0e81d9b401'),
name: 'product2',
price: 0.5,
description: 'Lorem ipsum.',
image: 'tomato',
},
];
Initialize stubs in the beforeEach()
method and provide them in configureTestingModule()
:
beforeEach(() => {
dbClientStub = {
collection: sinon.stub().returns({
aggregate: sinon.stub().returns({
toArray: (callbackFn: Function) =>
callbackFn(null, products),
}),
}),
};
transferStateStub = {
set: sinon.stub(),
};
TestBed.configureTestingModule({
providers: [
{
provide: 'dbConnection',
useValue: Promise.resolve(dbClientStub),
},
{
provide: TransferState,
useValue: transferStateStub,
},
],
});
service = TestBed.inject(ProductsServerService);
});
Notice that dbClientStub
and transferStateStub
are both created using the sinon.stub()
method. This lets you check inside tests if the service is calling MongoDB (rather than HTTP) to retrieve products. You will also check if it feeds up TransferState
with retrieved products by calling its set()
method.
Let's write the tests:
it('should initialize service', () => {
expect(service).toBeTruthy();
});
it('should query all products', async () => {
await service.getProducts().toPromise();
expect(
dbClientStub.collection().aggregate.calledOnce
).toBeTrue();
expect(
dbClientStub.collection().aggregate.getCall(0)
.args[0][0]
).toEqual({ $match: {} });
expect(transferStateStub.set.calledOnce).toBeTrue();
expect(transferStateStub.set.getCall(0).args).toEqual([
'products',
products,
]);
});
it('should query specific product', async () => {
await service
.getProduct('5ed3bbefaf1c4c0e81d9b400')
.toPromise();
expect(
dbClientStub.collection().aggregate.calledOnce
).toBeTrue();
expect(
dbClientStub.collection().aggregate.getCall(0)
.args[0][0]
).toEqual({
$match: { _id: ObjectId('5ed3bbefaf1c4c0e81d9b400') },
});
expect(transferStateStub.set.calledOnce).toBeTrue();
expect(transferStateStub.set.getCall(0).args).toEqual([
'product',
products[0],
]);
});
});
Similar to previous specs, the first test verifies that the service has been instantiated correctly. Next, you are testing the getProducts()
method of ProductsServerService
. Inside the test you verify that MongoDB has been called with a proper query:
expect(
dbClientStub.collection().aggregate.calledOnce
).toBeTrue();
expect(
dbClientStub.collection().aggregate.getCall(0)
.args[0][0]
).toEqual({ $match: {} });
This page is a preview of The newline Guide to Angular Universal