Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
mock-apollo-client
Advanced tools
The mock-apollo-client npm package is designed to help developers test their Apollo Client GraphQL queries and mutations by providing a way to mock the responses. This is particularly useful for unit testing and integration testing in a controlled environment without needing to rely on a live GraphQL server.
Mocking Queries
This feature allows you to mock GraphQL queries. The code sample demonstrates how to mock a query using the MockedProvider from @apollo/client/testing. The GET_DOGS query is mocked to return a predefined response.
const { MockedProvider } = require('@apollo/client/testing');
const { ApolloClient, InMemoryCache, gql } = require('@apollo/client');
const GET_DOGS = gql`
query GetDogs {
dogs {
id
breed
}
}
`;
const mocks = [
{
request: {
query: GET_DOGS,
},
result: {
data: {
dogs: [{ id: '1', breed: 'Bulldog' }],
},
},
},
];
const client = new ApolloClient({
cache: new InMemoryCache(),
});
<MockedProvider mocks={mocks} addTypename={false}>
<MyComponent />
</MockedProvider>;
Mocking Mutations
This feature allows you to mock GraphQL mutations. The code sample demonstrates how to mock a mutation using the MockedProvider from @apollo/client/testing. The ADD_DOG mutation is mocked to return a predefined response when called with specific variables.
const { MockedProvider } = require('@apollo/client/testing');
const { ApolloClient, InMemoryCache, gql } = require('@apollo/client');
const ADD_DOG = gql`
mutation AddDog($breed: String!) {
addDog(breed: $breed) {
id
breed
}
}
`;
const mocks = [
{
request: {
query: ADD_DOG,
variables: { breed: 'Bulldog' },
},
result: {
data: {
addDog: { id: '1', breed: 'Bulldog' },
},
},
},
];
const client = new ApolloClient({
cache: new InMemoryCache(),
});
<MockedProvider mocks={mocks} addTypename={false}>
<MyComponent />
</MockedProvider>;
Testing Error States
This feature allows you to test how your components handle error states. The code sample demonstrates how to mock an error response for a query using the MockedProvider from @apollo/client/testing. The GET_DOGS query is mocked to return an error.
const { MockedProvider } = require('@apollo/client/testing');
const { ApolloClient, InMemoryCache, gql } = require('@apollo/client');
const GET_DOGS = gql`
query GetDogs {
dogs {
id
breed
}
}
`;
const mocks = [
{
request: {
query: GET_DOGS,
},
error: new Error('An error occurred'),
},
];
const client = new ApolloClient({
cache: new InMemoryCache(),
});
<MockedProvider mocks={mocks} addTypename={false}>
<MyComponent />
</MockedProvider>;
@graphql-tools/mock provides utilities to mock GraphQL schema and resolvers. It is more focused on mocking the entire schema and generating mock data based on the schema definitions, which can be useful for more comprehensive testing scenarios.
graphql-mock is a lightweight library for mocking GraphQL queries and mutations. It provides a simple API to define mock responses and is suitable for unit testing. It is similar to mock-apollo-client but is not tied to Apollo Client.
msw (Mock Service Worker) is a versatile library for mocking network requests, including GraphQL. It intercepts requests at the network level, making it suitable for end-to-end testing. It provides more flexibility compared to mock-apollo-client, which is specifically designed for Apollo Client.
Helps unit test components which use the Apollo Client.
Version 0.x of this library is compatible with Apollo client 2
npm install --save-dev mock-apollo-client@apollo2
Version 1.x of this library is compatible with Apollo client 3
npm install --save-dev mock-apollo-client
Whilst using the impressive react-apollo
library, I ran into issues while trying to unit test components which used the GraphQL Query
and Mutation
components. The react-apollo
library includes a MockedProvider
component which allows query and mutation results to be mocked, but didn't offer enough control within unit tests. The react-apollo
documentation for testing can be found here.
Specifically, some of the issues I faced were:
MockProvider
was initialisedThe mock-apollo-client
library helps with the above issues, by allowing more control within unit tests.
npm install --save-dev mock-apollo-client@apollo2
Assuming mock-apollo-client
is being used within unit tests and should be installed as a dev dependency.
The examples below use react-apollo
, enzyme
and Jest
, but mock-apollo-client
is standalone and can used with any libraries and test frameworks.
The examples have been adapted from the official react-apollo
testing docs and are written in TypeScript.
Consider the file below, which contains a single GraphQL query and a component which is responsible for rendering the result of the query:
// dog.ts
import * as React from 'react';
import gql from 'graphql-tag';
import { Query } from 'react-apollo';
export const GET_DOG_QUERY = gql`
query getDog($name: String) {
dog(name: $name) {
id
name
breed
}
}
`;
export const Dog = ({ name }) => (
<Query query={GET_DOG_QUERY} variables={{ name }}>
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
return (
<p>
{data.dog.name} is a {data.dog.breed}
</p>
);
}}
</Query>
);
To unit test this component using mock-apollo-client
, the test file could look like the following:
// dog.test.ts
import { mount, ReactWrapper } from 'enzyme';
import * as React from 'react';
import { ApolloProvider } from 'react-apollo';
import { createMockClient } from 'mock-apollo-client';
import { GET_DOG_QUERY, Dog } from './dog';
let wrapper: ReactWrapper;
beforeEach(() => {
const mockClient = createMockClient();
mockClient.setRequestHandler(
GET_DOG_QUERY,
() => Promise.resolve({ data: { dog: { id: 1, name: 'Rufus', breed: 'Poodle' } } }));
wrapper = mount(
<ApolloProvider client={mockClient}>
<Dog name="Rufus" />
</ApolloProvider>
);
});
it('renders the dog name and breed', () => {
expect(wrapper.text()).toContain('Rufus is a Poodle');
});
This test file does the following:
setRequestHandler
on the mock Apollo client to set a function to be called when the Apollo client executes the Dog queryThe method setRequestHandler
is passed a function to call when Apollo client executes a given query and it is called with the variables for that query, so it is easy to assert the component is behaving as expected using a spy framework.
const queryHandler = jest.fn().mockResolvedValue({ data: { dog: { id: 1, name: 'Rufus', breed: 'Poodle' } } });
mockApolloClient.setRequestHandler(GET_DOG_QUERY, queryHandler);
// ....
it('executes the query with the correct variables', () => {
expect(queryHandler).toBeCalledTimes(1);
expect(queryHandler).toBeCalledWith({ name: 'Rufus' });
});
A request handler returns a promise, so testing for loading state just requires that the promise returned is not resolved or rejected.
To simulate a GraphQL network error, the request handler should return a rejected promise. i.e.
mockApolloClient.setRequestHandler(
GET_DOG_QUERY,
() => Promise.reject(new Error('GraphQL Network Error')));
To simulate GraphQL errors, the request handler should return a Promise which resolves with an errors
field. i.e.
mockApolloClient.setRequestHandler(
GET_DOG_QUERY,
() => Promise.resolve({ errors: [{message: 'GraphQL Error'}] }));
Mutations can be tested the same way that queries are, by using setRequestHandler
and specifying a request handler for the mutation query.
Subscriptions can be tested, but require a different setup as they receive a stream of data. Consider the file below, which contains a single subscription and a component which is responsible for rendering the updated data:
// dogSubscription.tsx
import * as React from 'react';
import gql from 'graphql-tag';
import { Subscription } from 'react-apollo';
export const SUBSCRIBE_DOG_DOCUMENT = gql`
subscription subscribeDog($name: String) {
dog(name: $name) {
id
name
numberOfBarks
}
}
`;
export const DogSubscription = ({ name }) => (
<Subscription subscription={SUBSCRIBE_DOG_DOCUMENT} variables={{ name }}>
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
return (
<p>
{data.dog.name} has barked {data.dog.numberOfBarks} time(s)
</p>
);
}}
</Subscription>
);
To unit test this component using mock-apollo-client
, the test file could look like the following:
// dogSubscription.test.tsx
import { mount, ReactWrapper } from 'enzyme';
import * as React from 'react';
import { ApolloProvider } from 'react-apollo';
import { createMockClient, createMockSubscription, IMockSubscription } from 'mock-apollo-client';
import { SUBSCRIBE_DOG_DOCUMENT, DogSubscription } from './dogSubscription';
let wrapper: ReactWrapper;
let mockSubscription: IMockSubscription;
beforeEach(() => {
const mockClient = createMockClient();
mockSubscription = createMockSubscription();
mockClient.setRequestHandler(
SUBSCRIBE_DOG_DOCUMENT,
() => mockSubscription);
wrapper = mount(
<ApolloProvider client={mockClient}>
<DogSubscription name="Rufus" />
</ApolloProvider>
);
});
it('renders the dog details', () => {
mockSubscription.next({ data: { dog: { id: 1, name: 'Rufus', numberOfBarks: 0 } } });
wrapper.update();
expect(wrapper.text()).toContain('Rufus has barked 0 time(s)');
mockSubscription.next({ data: { dog: { id: 1, name: 'Rufus', numberOfBarks: 1 } } });
wrapper.update();
expect(wrapper.text()).toContain('Rufus has barked 1 time(s)');
});
The subscription can be closed by calling .complete
if necessary for the test.
You can also test error states by calling .error
on the mockSubscription
and passing errors as described in Error States:
mockSubscription.error(new Error('GraphQL Network Error'))
A mock subscription will only be associated with a single invocation of a query. If a component is subscribing to the same query multiple times, then a separate mock subscription should be used for each one.
const subscriptions: IMockSubscription[] = [];
mockClient.setRequestHandler(
SUBSCRIBE_DOG_DOCUMENT,
() => {
const subscription = createMockSubscription();
subscriptions.push(subscription);
return subscription;
});
...
subscriptions.forEach((s) => s.next({ data: { dog: { id: 1, name: 'Rufus', numberOfBarks: 1 } } }));
The createMockClient
method can be provided with the same constructor arguments that ApolloClient
accepts which are used when instantiating the mock Apollo client.
For example, to specify the cache (and fragment matcher) that should be used:
const cache = new InMemoryCache({
fragmentMatcher: myCustomFragmentMatcher,
});
const mockClient = createMockClient({ cache });
Note: it is not possible to specify the link
to use as this is how Mock Apollo Client injects its behaviour.
If your queries or mutations use fragments, you must inject a cache object when creating the mock client which has been provided the fragment matcher and configured to add typenames.
For example, when using the IntrospectionFragmentMatcher:
import { IntrospectionFragmentMatcher, InMemoryCache } from 'apollo-cache-inmemory';
import { createMockClient } from 'mock-apollo-client';
import introspectionQueryResultData from './fragmentTypes.json';
const cache = new InMemoryCache({
addTypename: true,
fragmentMatcher: new IntrospectionFragmentMatcher({
introspectionQueryResultData,
}),
});
const mockClient = createMockClient({ cache });
You must then ensure that the query result includes the __typename
field as it would when calling your actual GraphQL API. This is to ensure that the fragment matching works as expected:
const query = gql`
query Hardware {
hardware {
id
... on Memory {
size
}
... on Cpu {
speed
}
}
}
`;
const mockData = {
hardware: {
__typename: 'Memory',
id: 2,
size: '16gb',
},
};
const requestHandler = jest.fn().mockResolvedValue({ data: mockData });
FAQs
Library to help unit testing when using apollo-client
The npm package mock-apollo-client receives a total of 146,714 weekly downloads. As such, mock-apollo-client popularity was classified as popular.
We found that mock-apollo-client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.