Components and utilities for testing GraphQL operations in React applications.
Mock Apollo Client provider for testing GraphQL operations without making real network requests.
/**
* Mock Apollo Client provider for testing GraphQL operations
*/
declare const MockProvider: React.ComponentType<MockProviderProps>;
interface MockProviderProps {
/** Array of mocked GraphQL responses */
mocks?: ReadonlyArray<MockedResponse>;
/** Whether to add __typename to responses */
addTypename?: boolean;
/** Default options for Apollo Client */
defaultOptions?: DefaultOptions;
/** Custom cache instance */
cache?: ApolloCache<any>;
/** Schema resolvers */
resolvers?: Resolvers;
/** Additional props passed to children */
childProps?: object;
/** React children */
children?: React.ReactElement;
/** Whether to show warnings for unmatched queries */
showWarnings?: boolean;
}
interface MockedResponse<TData = Record<string, any>, TVariables = Record<string, any>> {
/** GraphQL query/mutation/subscription to mock */
request: MockedRequest<TVariables>;
/** Mocked response data */
result?: MockedResult<TData>;
/** Error to return instead of result */
error?: Error;
/** Delay before returning response (ms) */
delay?: number;
/** How many times this mock can be used */
maxUsageCount?: number;
}
interface MockedRequest<TVariables = Record<string, any>> {
/** GraphQL query document */
query: DocumentNode;
/** Variables for the query */
variables?: TVariables;
/** Operation name */
operationName?: string;
/** Context for the request */
context?: Record<string, any>;
}
interface MockedResult<TData = Record<string, any>> {
/** Response data */
data?: TData;
/** GraphQL errors */
errors?: ReadonlyArray<GraphQLError>;
/** Extensions */
extensions?: any;
}Usage Examples:
import { MockProvider, gql } from "@apollo/react-hooks";
import { render, screen, waitFor } from "@testing-library/react";
const GET_USERS = gql`
query GetUsers {
users {
id
name
email
}
}
`;
const CREATE_USER = gql`
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
email
}
}
`;
// Basic mocking
const mocks = [
{
request: {
query: GET_USERS,
},
result: {
data: {
users: [
{ id: "1", name: "John Doe", email: "john@example.com" },
{ id: "2", name: "Jane Smith", email: "jane@example.com" },
],
},
},
},
{
request: {
query: CREATE_USER,
variables: {
input: { name: "New User", email: "new@example.com" },
},
},
result: {
data: {
createUser: {
id: "3",
name: "New User",
email: "new@example.com",
},
},
},
},
];
function UsersList() {
const { loading, error, data } = useQuery(GET_USERS);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data.users.map(user => (
<li key={user.id}>{user.name} - {user.email}</li>
))}
</ul>
);
}
test("renders user list", async () => {
render(
<MockProvider mocks={mocks} addTypename={false}>
<UsersList />
</MockProvider>
);
expect(screen.getByText("Loading...")).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText("John Doe - john@example.com")).toBeInTheDocument();
expect(screen.getByText("Jane Smith - jane@example.com")).toBeInTheDocument();
});
});Error Mocking:
import { MockProvider, gql, useQuery } from "@apollo/react-hooks";
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
const errorMocks = [
{
request: {
query: GET_USER,
variables: { id: "1" },
},
error: new Error("User not found"),
},
{
request: {
query: GET_USER,
variables: { id: "2" },
},
result: {
errors: [{ message: "Access denied" }],
},
},
];
function UserProfile({ userId }: { userId: string }) {
const { loading, error, data } = useQuery(GET_USER, {
variables: { id: userId },
});
if (loading) return <div>Loading user...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<h2>{data.user.name}</h2>
<p>{data.user.email}</p>
</div>
);
}
test("handles query errors", async () => {
render(
<MockProvider mocks={errorMocks}>
<UserProfile userId="1" />
</MockProvider>
);
await waitFor(() => {
expect(screen.getByText("Error: User not found")).toBeInTheDocument();
});
});Advanced Mocking with Dynamic Responses:
import { MockProvider, gql } from "@apollo/react-hooks";
const SEARCH_USERS = gql`
query SearchUsers($query: String!) {
searchUsers(query: $query) {
id
name
email
}
}
`;
// Mock with multiple usage count
const searchMocks = [
{
request: {
query: SEARCH_USERS,
variables: { query: "john" },
},
result: {
data: {
searchUsers: [
{ id: "1", name: "John Doe", email: "john@example.com" },
],
},
},
maxUsageCount: 3, // Can be used 3 times
},
{
request: {
query: SEARCH_USERS,
variables: { query: "jane" },
},
result: {
data: {
searchUsers: [
{ id: "2", name: "Jane Smith", email: "jane@example.com" },
],
},
},
delay: 1000, // 1 second delay
},
];
// Mock with custom resolvers
const mockResolvers = {
Query: {
users: () => [
{ id: "1", name: "Mock User 1", email: "mock1@example.com" },
{ id: "2", name: "Mock User 2", email: "mock2@example.com" },
],
},
Mutation: {
createUser: (_, { input }) => ({
id: Math.random().toString(),
...input,
}),
},
};
test("uses custom resolvers", async () => {
render(
<MockProvider resolvers={mockResolvers}>
<UsersList />
</MockProvider>
);
await waitFor(() => {
expect(screen.getByText("Mock User 1 - mock1@example.com")).toBeInTheDocument();
});
});interface DefaultOptions {
/** Default options for queries */
query?: Partial<QueryOptions>;
/** Default options for mutations */
mutate?: Partial<MutationOptions>;
/** Default options for watch queries */
watchQuery?: Partial<WatchQueryOptions>;
}
interface Resolvers {
[typeName: string]: {
[fieldName: string]: FieldResolver<any, any, any>;
};
}
type FieldResolver<TSource, TContext, TArgs> = (
source: TSource,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => any;
interface GraphQLError {
/** Error message */
message: string;
/** Error locations in query */
locations?: ReadonlyArray<SourceLocation>;
/** Error path */
path?: ReadonlyArray<string | number>;
/** Additional error data */
extensions?: Record<string, any>;
}
interface SourceLocation {
line: number;
column: number;
}