Dean James
Dean James

Reputation: 2623

Testing for types that are not optional

I'm reviewing some test-covered TypeScript (using Jest) that checks the return of some mandatory properties. However, some of these tests are checking what should happen if some of the mandatory properties are not set and I'm unsure how to best cover this in a typed way.

Here's an example of one of the functions:

const getPrice = (product: Product): number => product.price || 0;

The interface for Product is:

interface Product {
  name: string;
  price: number;
}

And the test:

describe('getPrice', ()  => {
  it('returns the price from the given order', () => {
    const mockProduct: Product = {name: 'mock product', price: 100};
    expect(getPrice(mockProduct)).toBe(100);
  });
  it('returns 0 if price is not defined in the given order', () => {
    const mockProduct: Product = {name: 'mock product'}; // Bad - Product requires price
    expect(getPrice(mockProduct)).toBe(0);
  });
});

The second test asserts against a lack of price property, however this is mandatory. I assume this is done because the real system may unexpectedly not have a price (the data comes from another service).

If so, should the price property in the interface be changed to optional? And would that also mean all properties that come from services should be optional?

Upvotes: 0

Views: 125

Answers (2)

Gilson Cavalcanti
Gilson Cavalcanti

Reputation: 1513

I think you should emulate the real situation in your test. In the getPrice function "point of view", it can receive anything from an external service. So it makes sense to set your partial test object as unknown and cast it to Product in your function call.

This way you're asserting to the typing system that you know what you're doing: "believe me! it's a Product here... i swear it!" 😀

Like this:

  it('returns 0 if price is not defined in the given order', () => {
    const mockProduct: unknown = {name: 'mock product'}; // Bad - Product requires price
    expect(getPrice(mockProduct as Product)).toBe(0);
  });

Upvotes: 2

Tim
Tim

Reputation: 2912

Totally depends on your usages. If you are making the types in your own code everywhere, you don't really have to test for undefined as you pointed out. Having said that, if you take them in from anywhere, or force cast anywhere then you are SOL.

Personally I don't worry about test types being perfect. So I would just make a Partial and then cast it

value as unknown as YourType

Will force it back to the correct type, but not require you to change application code at all. (Basically simulate outside values coming in)

Upvotes: 1

Related Questions