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);
  });
});