A mocked ApolloProvider solution that works equally well with Storybook and unit testing react components.
npm install apollo-mocked
or
yarn add apollo-mocked
Written in typescript, the apollo-mocked
packages exposes 3 components for testing loading, error, and mocked data.
All examples below will assume the following component:
import React from 'react';
import { useQuery } from '@apollo/client';
import gql from 'graphql-tag';
export const GET_DOG_QUERY = gql`
query getDog($name: String) {
dog(name: $name) {
id
name
breed
}
}
`;
export interface DogComponentProps {
name: string;
}
export const DogComponent: React.FC<DogComponentProps> = ({ name }) => {
const { data, loading, error } = useQuery(GET_DOG_QUERY, { variables: name });
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
return (
<p>
{data.dog.name} is a {data.dog.breed}
</p>
);
};
All components take an optional Provider
prop which will generally default to the latest ApolloProvider
from @apollo/react-hooks
. If your using a different version you will probably need to pass an instance of ApolloProvider
to each component.
property | propType | required | default |
---|---|---|---|
Provider | React.ComponentType<any> |
no | <ApolloProvider /> (@apollo/client v3.3.1) |
import React from 'react';
import { screen } from '@testing-library/react';
import { ApolloLoadingProvider } from 'apollo-mocked';
import { DogComponent } from './';
describe('Dog', () => {
it('should render loading component', async () => {
const loadingText = 'Loading...';
render(
<ApolloLoadingProvider>
<DogComponent name="Fido" />
</ApolloLoadingProvider>
);
const loadingNode = await screen.queryByText(loadingText);
expect(loadingNode).toBeInTheDocument();
expect(loadingNode).toHaveTextContent(new RegExp(`^${loadingText}$`));
});
});
import React from 'react';
import { ApolloLoadingProvider } from 'apollo-mocked';
import { DogComponent } from './';
export default {
title: 'Dogs',
component: DogComponent,
};
export const Loading = () => (
<ApolloLoadingProvider>
<DogComponent name="Fido" />
</ApolloLoadingProvider>
);
property | propType | required | default |
---|---|---|---|
Provider | React.ComponentType<any> |
no | <ApolloProvider /> (@apollo/client v3.3.1) |
errorMessages | string or string[] |
no | [new GraphQLError('Unspecified error from ErrorProvider.')] |
import React from 'react';
import { render, screen } from '@testing-library/react';
import { ApolloErrorProvider } from 'apollo-mocked';
import { DogComponent } from './';
describe('Dog', () => {
it('should render error component', async () => {
const errorMessage = 'Failed to fetch dog.';
render(
<ApolloErrorProvider errorMessages={errorMessage}>
<DogComponent name="Fido" />
</ApolloErrorProvider>
);
await wait(() => {
const errorNode = screen.getByText(errorMessage);
expect(errorNode).toBeInTheDocument();
expect(errorNode).toHaveTextContent(new RegExp(`^${errorMessage}$`));
});
});
});
import React from 'react';
import { ApolloErrorProvider } from 'apollo-mocked';
import { DogComponent } from './';
export default {
title: 'Dogs',
component: DogComponent,
};
export const Error = () => (
<ApolloErrorProvider>
<DogComponent name="Fido" />
</ApolloErrorProvider>
);
property | propType | required | default |
---|---|---|---|
Provider | React.ComponentType<any> |
no | <ApolloProvider /> (@apollo/client v3.3.1) |
addTypename | boolean | no | false |
cacheOptions | InMemoryCacheConfig |
no | -- |
clientOptions | ApolloClientOptions<NormalizedCacheObject> |
no | -- |
mocks | ReadonlyArray<MockedResponse> or LinkSchemaProps |
yes | -- |
linkSchemaProps
property | propType | required | default |
---|---|---|---|
introspectionResult | IntrospectionQuery |
yes | -- |
resolvers | IMocks |
yes | -- |
typeResolvers | IResolvers |
no | -- |
- using the
MockedResponse
type
const mocks = [
{
request: {
query: GET_DOG_QUERY,
variables: {
name: 'Fido',
},
},
result: {
data: {
dog: { id: '1', name: 'Fido', breed: 'bulldog' },
},
},
},
];
- using the
createMocks
util (outputsMockedResponse[]
like above)
import { createMocks } from 'apollo-mocked';
import { DOG_QUERY } from './dogQuery';
export const dogMocks = createMocks<DogQuery, DogQueryVariables>(DOG_QUERY, {
data: {
dog: { id: '1', name: 'Fido', breed: 'bulldog' },
},
variables: { name: 'Fido' },
});
- using the
IMocks
type
Note: the typeDefs
const below can also be a json file (result of introspecting schema)
const typeDefs = gql`
type Query {
hello: String
resolved: String
}
`;
const resolvers = {
Query: {
getDog: () => {
id: '1',
name: 'Fido',
breed: 'bulldog'
},
},
};
const mocks = {
introspectionResult: typeDefs,
resolvers,
};
import React from 'react';
import { render, screen, wait } from '@testing-library/react';
import { ApolloMockedProvider } from 'apollo-mocked';
import { mocks } from './example-above';
import { DogComponent } from './';
describe('Dog', () => {
it('should render the dog name', async () => {
const dogName = 'Fido';
render(
<ApolloMockedProvider mocks={mocks}>
<DogComponent name="Fido" />
</ApolloErrorProvider>
);
await wait(() => {
const dogNameNode = screen.getByText(dogName);
expect(dogNameNode).toBeInTheDocument();
expect(dogNameNode).toHaveTextContent(new RegExp(`^${dogName}$`));
});
});
});
import React from 'react';
import { ApolloMockedProvider } from 'apollo-mocked';
import { mocks } from './example-above';
import { DogComponent } from './';
export default {
title: 'Dogs',
component: DogComponent,
};
export const DogName = () => (
<ApolloMockedProvider mocks={mocks}>
<DogComponent name="Fido" />
</ApolloMockedProvider>
));