npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sourceallies/apollo-schema-mocks

v1.2.1

Published

Schema-aware GraphQL mocking utilities for Apollo Client + Vitest testing

Readme

@sourceallies/apollo-schema-mocks

Schema-aware GraphQL mocking utilities for Apollo Client + Vitest testing.

Features

  • Schema-based mocking - Uses your actual GraphQL schema for type-safe mocks
  • Spy/mock separation - Track calls separately from return values (prevents nested mock issues)
  • Sequential responses - mockReturnValueOnce() support for refetch/pagination testing
  • Scalar success values - scalarSuccess() for queries that return scalar types (String!, ID!, etc.)
  • Conditional mocks - createConditionalResolver() for variable-dependent behavior
  • Flexible schema input - Accepts IntrospectionQuery, SDL string, or GraphQLSchema
  • Schema caching - Improves test performance with WeakMap-based caching
  • Error mock helpers - Pre-built helpers for common error scenarios
  • Framework-agnostic - Works with React, Vue, Angular, Svelte, or any Apollo Client usage

Installation

npm install --save-dev @sourceallies/apollo-schema-mocks

Peer Dependencies

  • @apollo/client ^3.0.0
  • graphql ^16.0.0
  • vitest >=1.0.0 (optional, required for spy mocks)

Quick Start

Basic Usage

import { createMockApolloClientWithSchema } from '@sourceallies/apollo-schema-mocks';
import introspectionResult from './schema.json';

// Create a mock Apollo Client
const { client, schema } = createMockApolloClientWithSchema({
  schema: introspectionResult,
  queryMocks: {
    getUser: () => ({ id: '1', name: 'Alice', email: '[email protected]' }),
    getUsers: () => [{ id: '1', name: 'Alice' }, { id: '2', name: 'Bob' }],
  },
  mutationMocks: {
    createUser: () => ({ id: 'new-1', name: 'NewUser' }),
  },
});

// Use the client in your tests
const result = await client.query({ query: GET_USER, variables: { id: '1' } });

Using Spy Mocks for Assertions

Spy mocks let you verify how operations were called while returning mock data:

import {
  createMockApolloClientWithSchema,
  createQuerySpyMocks,
  createMutationSpyMocks,
  combineFieldMocks,
} from '@sourceallies/apollo-schema-mocks';

// Create spy mocks - spies are separate from mocks
const { spies: querySpies, mocks: queryMocks } = createQuerySpyMocks({
  getUser: { id: '1', name: 'Alice' },
  getUsers: [{ id: '1', name: 'Alice' }, { id: '2', name: 'Bob' }],
});

const { spies: mutationSpies, mocks: mutationMocks } = createMutationSpyMocks({
  createUser: { id: 'new-1', name: 'NewUser' },
});

// Combine query and mutation mocks
const combined = combineFieldMocks(
  queryMocks,
  mutationMocks,
);

// Create the mock client
const { client } = createMockApolloClientWithSchema({
  schema: introspectionResult,
  queryMocks: combined.Query,
  mutationMocks: combined.Mutation,
});

// Run your test
await client.query({ query: GET_USER, variables: { id: '1' } });
await client.mutate({ mutation: CREATE_USER, variables: { input: { name: 'Alice' } } });

// Assert on spies
expect(querySpies.getUser).toHaveBeenCalledWith({ id: '1' });
expect(mutationSpies.createUser).toHaveBeenCalledWith({ input: { name: 'Alice' } });

Sequential Responses with mockReturnValueOnce

Spy mocks support mockReturnValueOnce() for testing refetch, pagination, and optimistic update scenarios:

const { spies, mocks, mockData } = createQuerySpyMocks({
  getOrders: { orders: [order1, order2], totalCount: 2 },
});

// Override the first call to return different data
spies.getOrders.mockReturnValueOnce({ orders: [order1], totalCount: 1 });

// First call returns the override (1 order)
// Subsequent calls return the default mockData (2 orders)

Scalar Success Values

When mocking queries that return scalar types (String!, ID!, Int!), use scalarSuccess() to distinguish from error strings:

import { createQuerySpyMocks, scalarSuccess } from '@sourceallies/apollo-schema-mocks';

const { mocks } = createQuerySpyMocks({
  getEmailBody: scalarSuccess('Hello, this is the email body'),
  getUserCount: scalarSuccess(42),
  isFeatureEnabled: scalarSuccess(true),
});

Without scalarSuccess(), a plain string like 'Hello' would be treated as an error message.

Conditional Mocks

For mocks that need to return different results based on variables at call time:

import { createConditionalResolver } from '@sourceallies/apollo-schema-mocks';

// Use directly as a query/mutation mock
const { client } = createMockApolloClientWithSchema({
  schema: introspectionResult,
  queryMocks: {
    getUser: createConditionalResolver(
      (vars) => (vars as { id: string }).id === '123',
      { id: '123', name: 'Alice' },
      'User not found',
    ),
  },
});

Error Mocks

Test error handling with pre-built error helpers:

import {
  createQuerySpyMocks,
  createErrorMock,
  createAuthenticationError,
  createAuthorizationError,
  createNotFoundError,
  createValidationError,
} from '@sourceallies/apollo-schema-mocks';

const { mocks } = createQuerySpyMocks({
  // Custom error
  getUser: createErrorMock('User not found', { extensions: { code: 'NOT_FOUND' } }),

  // Pre-built error helpers
  getSecretData: createAuthenticationError(),
  getAdminData: createAuthorizationError(),
  getProfile: createNotFoundError('Profile', '123'),
});

const { mocks: mutationMocks } = createMutationSpyMocks({
  createUser: createValidationError('Email is required', ['input', 'email']),
});

// Simple string errors
const { mocks: errorMocks } = createQuerySpyMocks({
  getUser: 'User not found',  // Throws GraphQLError with this message
});

Available error helpers:

  • createErrorMock(message, options) - Custom error with extensions
  • createMultipleErrorsMock(errors) - Multiple errors in one response
  • createAuthenticationError(message?) - UNAUTHENTICATED error
  • createAuthorizationError(message?) - FORBIDDEN error
  • createValidationError(message, field?) - VALIDATION_ERROR error
  • createNotFoundError(resource, id?) - NOT_FOUND error
  • createInternalError(message?) - INTERNAL_SERVER_ERROR error
  • createNetworkError(message?) - NETWORK_ERROR error
  • conditionalErrorMock(condition, error, data) - Return error or data based on condition
  • createConditionalResolver(condition, data, error) - Variable-dependent success/error at call time

Schema Caching

The library automatically caches built schemas for performance:

import { schemaCacheStats, clearSchemaCache } from '@sourceallies/apollo-schema-mocks';

// Check cache performance
console.log(schemaCacheStats.hitRate); // e.g., 0.95
console.log(schemaCacheStats.hits);    // e.g., 19
console.log(schemaCacheStats.misses);  // e.g., 1

// Reset stats between test suites if needed
schemaCacheStats.reset();

// Clear cache if needed (rarely necessary)
clearSchemaCache();

Custom Scalar Mocks

Override the default scalar mocks or add your own:

const { client } = createMockApolloClientWithSchema({
  schema: introspectionResult,
  scalars: {
    Date: () => '2024-01-15',
    DateTime: () => '2024-01-15T10:30:00Z',
    JSON: () => ({ custom: 'data' }),
    CustomScalar: () => 'custom-value',
  },
  queryMocks: {
    // ...
  },
});

Default scalar mocks:

  • String - "mock-string"
  • Int - 42
  • Float - 3.14
  • Boolean - true
  • ID - "mock-id"
  • Date - "2024-01-01"
  • DateTime - "2024-01-01T00:00:00Z"
  • JSON - Empty object
  • BigInt - Max safe integer as string

API Reference

Core

| Function | Description | |----------|-------------| | createMockApolloClientWithSchema(options) | Creates a mock Apollo Client with schema-based mocks | | getOrBuildSchema(input) | Builds or retrieves a cached GraphQL schema | | clearSchemaCache() | Clears the schema cache | | schemaCacheStats | Object with cache hit/miss statistics |

Helpers

| Function | Description | |----------|-------------| | createQuerySpyMocks(mocks) | Creates query mocks with spies for assertions | | createQueryMocks(mocks) | Creates simple query mocks without spies | | createQueryMock(name, value) | Creates a single query mock | | createMutationSpyMocks(mocks) | Creates mutation mocks with spies | | createMutationMocks(mocks) | Creates simple mutation mocks | | createMutationMock(name, value) | Creates a single mutation mock | | createSubscriptionSpyMocks(mocks) | Creates subscription mocks with spies | | createSubscriptionMocks(mocks) | Creates simple subscription mocks | | createSubscriptionMock(name, value) | Creates a single subscription mock | | combineFieldMocks(...results) | Combines multiple mock results | | scalarSuccess(value) | Wraps a scalar value for successful mock returns | | isScalarSuccess(value) | Type guard for scalar success values | | isErrorMock(value) | Type guard for error mocks | | createConditionalResolver(condition, data, error) | Variable-dependent mock |

Schema Input Formats

The library accepts schemas in multiple formats:

// 1. IntrospectionQuery (from graphql-codegen or similar)
import introspection from './schema.json';
createMockApolloClientWithSchema({ schema: introspection, ... });

// 2. SDL string
const sdl = `
  type Query {
    user(id: ID!): User
  }
  type User {
    id: ID!
    name: String!
  }
`;
createMockApolloClientWithSchema({ schema: sdl, ... });

// 3. GraphQLSchema object
import { buildSchema } from 'graphql';
const schema = buildSchema(sdl);
createMockApolloClientWithSchema({ schema, ... });

Why Spy/Mock Separation?

Traditional mocking approaches often use vi.fn().mockReturnValue() directly as resolvers. This causes issues with nested mock values because Vitest's mock functions have additional properties that interfere with GraphQL field resolution.

This library separates concerns:

  • Spies are Vitest mock functions for tracking calls, with mockImplementation returning the mock data
  • Mocks are plain functions that delegate to the spy
// WRONG - causes nested mock value issues
const userMock = vi.fn().mockReturnValue({ id: '1', name: 'Alice' });
// userMock has extra properties that confuse GraphQL

// CORRECT - this library's approach
const { spies, mocks } = createQuerySpyMocks({
  user: { id: '1', name: 'Alice' },
});
// spies.user is for assertions (default implementation returns mock data)
// mocks.Query.user delegates to the spy and returns clean data
// spies.user.mockReturnValueOnce() can override responses for one call

Documentation

Requirements

  • Node.js >= 18
  • Apollo Client >= 3.0.0
  • GraphQL >= 16.0.0

License

MIT - See LICENSE for details.