Stubbing interfaces in Typescript
↳ Typescript
17 Apr 2020 | 4 minute read
When writing tests for functions that have parameters of large interfaces, handcrafting the parameter objects is cumbersome. Say for example, that you want to test the following function.
const getPhysicalBasketItems = (items: BasketItem[]): BasketItem[] => {
return items.filter((item) => item.name !== 'Shipping');
};
It accepts an array
of BasketItem
objects, and returns all BasketItem
objects that don't have the name "Shipping"
. It's a simple function, and testing it should be easy. But what if the interface
looks like this?
export interface BasketItem {
id?: number;
lineNo: number;
productId: number;
partNo: string;
manufacturerPartNo: string;
name: string;
subHeader: string;
thumbnailImage: string;
imageKey: string;
flagIdSeed: string;
type: number;
priceDisplay: number;
price?: number;
priceOriginal: number;
cost?: number;
vatRate: number;
quantity: number;
UOM: string;
UOMCount?: number;
comment: string;
priceListId: number;
referId?: number;
referUrl: string;
isEditable: boolean;
isDiscountable: boolean;
onHandValue: number;
incomingValue: number;
nextDeliveryDate?: Date;
leadtimeDayCount?: number;
onHand: {
value: number;
};
}
Handcrafting various BasketItem
objects isn't feasible.
This is where type assertions come in handy. We can use type assertions to create our objects, and only the define the attributes we need. Our BasketItem
objects can be initialised using type assertions like this:
const basketItem1 = {} as BasketItem;
const basketItem2 = { name: 'Shipping' } as BasketItem;
Using these objects, we can test our function in a simple way.
describe('getPhysicalBasketItems', (): void => {
test('Removes shipping items', (): void => {
const basketItem1 = {} as BasketItem;
const basketItem2 = { name: 'Shipping' } as BasketItem;
const basketItems = [basketItem1, basketItem2];
const physicalBasketItems = getPhysicalBasketItems(basketItems);
expect(physicalBasketItems.length).toEqual(1);
expect(physicalBasketItems[0]).toEqual(basketItem1);
});
});