GraphQL Mocking for Frontend and API Tests
AI generated
{ }
type
GraphQL · Mocking · Testing · MSW · Apollo
GraphQL Mocking for Frontend and API Tests
Using schema, MSW and MockedProvider the right way

Without mocking, an unfinished backend endpoint blocks the entire frontend development effort. GraphQL mocking at the schema level makes frontend teams independent, enables testing of error scenarios, and significantly speeds up the development cycle.

15 min read MSW · Apollo MockedProvider · Schema Mocking · Magento React · TypeScript · Vitest · Playwright

1. Why GraphQL mocking is more than dummy data

The most obvious approach in the frontend: create a JavaScript file with hardcoded test data and pass it into component props. That works for individual unit tests, but it fails as soon as a component itself fires a GraphQL query, as soon as network loading times need to be simulated, or as soon as error paths need to be tested. Real GraphQL mocking operates at the level of the network handler or the GraphQL client and intercepts queries exactly the way a real server would.

The benefits go far beyond isolation. A good mock also simulates slow networks, authentication failures, partial data errors within a response, and timeout behavior. Anyone who only works with static fixture files gets reliable tests for the success path, but no confidence for the cases that most often lead to support tickets in production. GraphQL mocking at the schema level also ensures that mocked data is always schema-compliant: a mock that does not match the schema fails early in the development process, not in production.

2. Schema-based mocking: addMocksToSchema

Getting started with schema-based GraphQL mocking begins with the @graphql-tools/mock package. The addMocksToSchema function takes an existing schema object and automatically augments every resolver with realistic default values: strings are mocked as empty strings, integers as 42, booleans as false. For production-ready tests, these defaults are overridden with custom mock resolvers per type and field. The schema itself is either loaded from the SDL or obtained via introspection from the real endpoint.

The decisive advantage of this approach: the mock responses are processed through the full GraphQL execution stack. That means validation, type checking, and field resolution all run exactly as they would on the real server. If a client sends a query that does not match the schema, it also fails against the mock, which moves errors that would otherwise only surface during real API calls into local development time. For teams working schema-first, this is the preferred approach: lock down the schema, spin up a mock server, start frontend development, without waiting for the backend implementation.


# Mock schema for a product catalog (schema-first approach)
# This schema is used by addMocksToSchema

type Query {
  product(sku: String!): Product
  products(search: String, pageSize: Int): ProductList!
  cart(cartId: String!): Cart
}

type Product {
  sku: String!
  name: String!
  price_range: PriceRange!
  stock_status: StockStatus!
  description: String
}

type ProductList {
  items: [Product!]!
  total_count: Int!
}

type PriceRange {
  minimum_price: Price!
}

type Price {
  final_price: Money!
}

type Money {
  value: Float!
  currency: String!
}

type Cart {
  id: String!
  items: [CartItem!]!
  prices: CartPrices!
}

type CartItem {
  uid: String!
  quantity: Int!
  product: Product!
}

type CartPrices {
  grand_total: Money!
}

enum StockStatus {
  IN_STOCK
  OUT_OF_STOCK
}

3. MSW in the browser: queries without a real server

Mock Service Worker (MSW) is the preferred approach for browser-based GraphQL mocking because it operates on the browser's Service Worker API and thereby intercepts real network requests. The frontend code's behavior does not change at all: it sends real fetch requests, which MSW intercepts and answers with configured responses. Unlike monkey-patching fetch or Axios adapters, MSW works with any HTTP library and also in Playwright E2E tests.

For GraphQL queries, MSW offers the graphql.query() and graphql.mutation() handlers. The handler matches on the operation name, not on the URL alone, which makes it easy to configure multiple endpoints with different responses. In development environments, MSW is activated via service worker registration in the browser; in Vitest or Jest, MSW runs through Node interceptors without a service worker. The same handler code therefore works across every test level, which ensures consistency between unit, integration, and E2E tests.


# Intercepted query: MSW matches on the operation name "GetProduct"
# The handler in handlers.ts returns this structure as the response

query GetProduct($sku: String!) {
  product(sku: $sku) {
    sku
    name
    price_range {
      minimum_price {
        final_price {
          value
          currency
        }
      }
    }
    stock_status
    description
  }
}

# Error case query: same operation, MSW handler returns errors[]
# Tests error handling in the frontend without changing the server
query GetProductError($sku: String!) {
  product(sku: $sku) {
    sku
    name
  }
}

4. Apollo MockedProvider for component tests

Anyone using Apollo Client in a React frontend gets a direct mocking solution for component tests with MockedProvider. The MockedProvider replaces the real Apollo client in the test render tree and answers defined queries with prepared responses. Configuration happens via an array of MockedResponse objects, each of which contains a query operation and the desired response or an error.

A common pitfall with Apollo MockedProvider: queries must match exactly, including variables. If the query used in the test does not match the one in the component bit for bit, for example due to different fragment definitions or variable defaults, the MockedProvider returns no response and the test fails with a timeout error. It is therefore good practice to define GraphQL documents as .graphql files that are imported both in production code and in tests. In addition, the addTypename: false parameter of the MockedProvider offers a simplification for tests that do not need __typename fields.

5. Mocking error scenarios and partial errors

GraphQL errors have a special structure: unlike HTTP errors, GraphQL responses can contain both data and errors at the same time. A partial error occurs when a resolver for an optional field fails while other fields are populated correctly. In this case, the frontend has to decide whether and how to display the partial data. This scenario is barely testable with static fixture data; a good mock setup makes it possible to deliberately generate such responses.

With MSW, both data and errors are returned in the response object to simulate partial errors. In Apollo MockedProvider, the error property of a MockedResponse is used for network errors, and the result.errors array is used for GraphQL errors within a successful HTTP response. Anyone who does not model this distinction in tests gets no statement about whether the frontend reacts correctly to Apollo's error boundary behavior, or whether a loading indicator gets stuck when a resolver silently fails.


# Partial error: cart is returned correctly,
# but the field "shipping_addresses" fails in the resolver.
# MSW handler returns this structure to test frontend behavior.

# Expected response structure (JSON):
# {
#   "data": {
#     "cart": {
#       "id": "abc123",
#       "items": [...],
#       "prices": { "grand_total": { "value": 89.99, "currency": "EUR" } },
#       "shipping_addresses": null
#     }
#   },
#   "errors": [
#     {
#       "message": "Shipping address resolver failed",
#       "path": ["cart", "shipping_addresses"],
#       "extensions": { "category": "graphql-authorization" }
#     }
#   ]
# }

query GetCart($cartId: String!) {
  cart(cartId: $cartId) {
    id
    items {
      uid
      quantity
      product { sku name }
    }
    prices {
      grand_total { value currency }
    }
    shipping_addresses {
      city
      postcode
    }
  }
}

6. Mocking for Magento GraphQL endpoints

With Magento GraphQL, a few specific challenges come into play that make mocking more complex. Magento queries run against a single endpoint (/graphql), but use store-specific headers such as Store: de and optional authentication bearer tokens for customer context. MSW handlers can evaluate these headers and deliver different mock responses for guest and customer sessions. This is especially valuable when testing headless frontends that handle cart, checkout, and customer account flows via GraphQL.

Another Magento-specific aspect: many production Magento GraphQL queries use inline fragments on union types such as ProductInterface to distinguish between SimpleProduct, ConfigurableProduct, and other product types. In the mock, the __resolveType field must be set correctly so that the GraphQL execution stack knows which concrete type to resolve. Schema-based mocking with addMocksToSchema solves this automatically, provided the mock resolver for ProductInterface returns a concrete type.


# Typical Magento query with union type inline fragments
# Must return __resolveType correctly in the mock

query GetProductDetails($sku: String!) {
  products(filter: { sku: { eq: $sku } }) {
    items {
      __typename
      sku
      name
      price_range {
        minimum_price {
          final_price { value currency }
        }
      }
      ... on ConfigurableProduct {
        configurable_options {
          attribute_code
          label
          values { uid label swatch_data { value } }
        }
        variants {
          product { sku name }
          attributes { uid label code value_index }
        }
      }
      ... on SimpleProduct {
        stock_status
        only_x_left_in_stock
      }
    }
  }
}

7. Contract tests between the mock and the real schema

Contract tests close the dangerous gap between mocks and reality: they ensure that the mocked schema matches the real production schema. Without contract tests, mocks can go stale: a mutation gains new required fields, a type gets renamed, a field receives a different return type. The mock-based component test keeps running green while the production code breaks.

The tool of choice is GraphQL Inspector, which compares two schemas and identifies breaking changes. In the CI process, a job loads the current schema from the production endpoint via introspection and compares it with the schema the mock handlers are based on. If there are discrepancies, the CI build fails before the code goes to production. For Magento projects, it is also advisable to store the schema snapshot in the repository, so that schema diffs can be detected even without network access to the production system.

8. Comparing mocking strategies

Different test levels call for different GraphQL mocking strategies. Choosing the right approach depends on the test goal, the GraphQL client in use, and the desired level of isolation.

Strategy Use case Advantage Limitation
addMocksToSchema Local mock server, Storybook Schema-validated, all types automatic No network interception
MSW (graphql.query) Unit, integration, E2E tests Real network stack, client-agnostic No schema validation by default
Apollo MockedProvider React component tests Exact query control, cache state Apollo-specific, requires exact match
Fixtures (JSON) Simple unit tests, snapshots Fast, no setup required No error scenarios, goes stale quickly
Contract tests (Inspector) CI pipeline, schema drift detection Prevents mock-reality drift Requires schema access in CI

In practice, several strategies are combined: addMocksToSchema for the local development server and Storybook, MSW for Vitest and Playwright tests, and Apollo MockedProvider for isolated component tests. The contract tests run once a day in the CI pipeline and raise an alarm on schema drift before a new frontend release is deployed.

9. Summary

Effective GraphQL mocking for frontend and API tests requires more than static fixture files. Schema-based mocking with addMocksToSchema ensures that mock responses are always schema-compliant. MSW enables real network interception that works consistently across unit, integration, and E2E tests. Apollo MockedProvider gives full control over Apollo cache state and query matching in component tests. Combining these strategies reduces flaky tests, covers error paths, and makes frontend teams independent of the backend's development status.

Contract tests between the mock schema and the production schema are the decisive safeguard against the most common long-term mistake: mocks that stay green while the real schema has long since evolved. With GraphQL Inspector in the CI process, this drift is detected automatically before it turns into a production problem.

GraphQL Mocking for Frontend and API Tests: Key Takeaways at a Glance

Schema mocking

addMocksToSchema validates mock responses against the real schema, preventing mock drift in local development and in Storybook.

MSW for every test level

Mock Service Worker intercepts real network requests, works client-agnostically, and is consistent across unit, integration, and E2E tests.

Error paths

Deliberately mock partial GraphQL errors (data + errors) to test error handling, loading indicator behavior, and error boundaries in the frontend.

Contract tests

GraphQL Inspector in CI compares the mock schema with the production schema, raising an alarm on breaking changes before they reach production.

11. FAQ: GraphQL Mocking for Frontend and API Tests

1MSW vs. Apollo MockedProvider?
MSW intercepts real network requests, is client-agnostic, and works in unit, integration, and E2E tests. Apollo MockedProvider is Apollo-specific but offers direct cache control and is ideal for isolated component tests.
2How do you prevent mock drift?
GraphQL Inspector in CI compares the mock schema with the production schema. Schema-first development ensures that mocks are created directly from the SDL and stay current automatically.
3MSW in Playwright E2E tests?
Yes. The same MSW handlers work in Vitest (Node interceptor) and Playwright (service worker in the browser). A single handler file for every test level.
4Mocking partial GraphQL errors?
GraphQL responses can contain both data and errors at the same time. MSW returns both in the response object. Apollo MockedProvider distinguishes between result.errors (GraphQL errors) and error (network errors).
5Apollo MockedProvider timeout errors?
Usually a query mismatch. The query in the component must match the one defined in the mock bit for bit. Share GraphQL documents as .graphql files instead of duplicating them.
6Mocking Magento authentication in tests?
MSW handlers evaluate the Authorization header and deliver different responses for guests and customers. Login flows, cart state, and customer-specific pricing become testable without a real Magento server.
7addMocksToSchema type-safe in TypeScript?
Yes, in combination with GraphQL Code Generator. Use generated TypeScript types for mock resolvers so mock data is checked at compile time.
8Mocking Magento union types?
addMocksToSchema resolves union types automatically when the mock resolver returns a concrete type. __resolveType decides between SimpleProduct and ConfigurableProduct.
9Using the same mock in Storybook and tests?
With MSW and the Storybook addon. The same handler definitions in Storybook and in tests: a single source of truth for mock data.
10Testing loading times and timeouts?
MSW handlers delay responses with delay() or return none at all. This makes it possible to reliably test skeleton loaders, error boundaries, and retry logic.