unit-testingapollo-clientgraphql-codegen

MockedProvider from @apollo/client/testing has issues with union types


Sorry if this post has a lot of code, but I feel like its necessary in order to get the full context. Bear in mind we are using Jest + @testing-library/react + @apollo/client/testing for testing, the mocks are created with plugin into @graphql-codegen called typescript-mock-data, and our app is made of NextJS + ApolloGrapql

given the facts from our schema.graphql:

union Facet = FacetColor | FacetSize | FacetText | FacetRange

type ProductListResult {
  facets: [Facet]
}

and our mocked created with codegen with the typescript-mock-data plugin (the mock is created based on types.ts which is based on schema.graphql):

export const aProductListResult = (overrides?: Partial<ProductListResult>, _relationshipsToOmit: Set<string> = new Set()): { __typename: 'ProductListResult' } & ProductListResult => {
    const relationshipsToOmit: Set<string> = new Set(_relationshipsToOmit);
    relationshipsToOmit.add('ProductListResult');
    return {
        __typename: 'ProductListResult',
        facets: overrides && overrides.hasOwnProperty('facets') ? overrides.facets! : [relationshipsToOmit.has('FacetColor') ? {} as FacetColor : aFacetColor({}, relationshipsToOmit)],
    };
};

In the mock we can see that aProductListResults gives us a property "facets" that is an array with a single FacetColor-object. When feeding this mock into MockedProvider from apollo, The mocked FacetColor only contains { __typename: FacetColor }, without any other properties which is really weird because aFacetColor-mock which is used in aProductListResult contains these properties:

export const aFacetColor = (overrides?: Partial<FacetColor>, _relationshipsToOmit: Set<string> = new Set()): { __typename: 'FacetColor' } & FacetColor => {
    const relationshipsToOmit: Set<string> = new Set(_relationshipsToOmit);
    relationshipsToOmit.add('FacetColor');
    return {
        __typename: 'FacetColor',
        id: overrides && overrides.hasOwnProperty('id') ? overrides.id! : 'est',
        label: overrides && overrides.hasOwnProperty('label') ? overrides.label! : 'magnam',
        selectedCount: overrides && overrides.hasOwnProperty('selectedCount') ? overrides.selectedCount! : 2694,
        values: overrides && overrides.hasOwnProperty('values') ? overrides.values! : [relationshipsToOmit.has('FacetColorItem') ? {} as FacetColorItem : aFacetColorItem({}, relationshipsToOmit)],
    };
};

The only logical explanation we've came up with so far is that Facet from schema.graphql is a union type and for some reason the MockedProvider used for unittesting can't manage to resolve the union types. This is confirmed by testing other types that aren't union types. Does anyone have any clue on what's happening? Several hours of googling did not get me anywhere...

how we use the MockedProvider:

export const productListMock = () => {
  return {
    request: {
      query: ProductsDocument,
      variables: {
        params: {
          url: '/no/dame/kolleksjon/nyheter/',
          limit: 30,
          sort: 'NEWEST_FIRST',
          facetFilter: [],
          skip: 0,
          hiddenFacet: ['perferendis'],
          productRules: 'similique',
        },
      },
    },
    result: {
      data: {
        products: aProductListResult({ products: Array(30).fill(aProduct()) }),
      },
    },
  };
};
<--- this part is from the unit test inside a describe function --->
<MockedApolloProvider mocks={[productListMock()]}>
    <ProductListPage />
</MockedApolloProvider>

Solution

  • If you have union types, the MockProvider needs a cache with possibleTypes just like the cache you're using in your app:

    <MockedApolloProvider mocks={[productListMock()]} cache={new InMemoryCache({ possibleTypes })}>
        <ProductListPage />
    </MockedApolloProvider>