Testing GraphQL APIs

1. Setting Up Test Environment

ToolUse
Vitest / JestTest runner
graphql / @graphql-tools/executorIn-process execution
TestcontainersReal DB in CI
MSWMock HTTP responses for client tests

2. Testing Queries

Example: In-process query test

import { graphql } from "graphql";
import { schema } from "../src/schema";

test("user query returns name", async () => {
  const result = await graphql({
    schema,
    source: `query U($id: ID!) { user(id: $id) { name } }`,
    variableValues: { id: "1" },
    contextValue: { db: testDb, user: testUser }
  });
  expect(result.errors).toBeUndefined();
  expect(result.data.user.name).toBe("Ada");
});

3. Testing Mutations

Example: Mutation test

test("createPost", async () => {
  const r = await graphql({ schema, source: CREATE_POST, variableValues: { input }, contextValue });
  expect(r.data.createPost.post.id).toBeDefined();
  expect(await testDb.post.count()).toBe(1);
});

4. Testing Subscriptions

Example: Subscribe test

import { subscribe, parse } from "graphql";

const iter = await subscribe({ schema, document: parse(SUB_QUERY), contextValue });
pubsub.publish("EVENT", { messageAdded: { id: "1", body: "hi" } });
const { value } = await iter.next();
expect(value.data.messageAdded.body).toBe("hi");

5. Testing Resolvers

StrategyDetail
Unit (call resolver directly)Fast, isolated
Integration (via graphql())Tests selection + parse + validate
E2E (HTTP)Tests middleware, auth, transport

6. Mocking Data Sources

Example: Schema mocking

import { addMocksToSchema } from "@graphql-tools/mock";

const mocked = addMocksToSchema({
  schema,
  mocks: { User: () => ({ name: "Mock", email: "m@x.co" }) }
});

7. Testing Error Handling

AssertionDetail
errors[0].messageVerify content (or absence)
errors[0].extensions.codeCode-level assertion
errors[0].pathWhere it occurred
data preservedPartial-data behavior

8. Testing Authentication

Example: Auth scenarios

test.each([
  ["anonymous", null, "UNAUTHENTICATED"],
  ["non-admin", { id: "u1", role: "USER" }, "FORBIDDEN"],
  ["admin", { id: "u2", role: "ADMIN" }, undefined]
])("admin op as %s", async (_, user, code) => {
  const r = await graphql({ schema, source: ADMIN_OP, contextValue: { user } });
  expect(r.errors?.[0]?.extensions.code).toBe(code);
});

9. Testing Authorization

PatternDetail
Negative testVerify forbidden access throws
Positive testVerify owner/admin succeeds
Field-levelVerify masked fields return null

10. Using Schema Testing

ToolDetail
graphql-inspectorDiff old vs new for breaking changes
graphql-eslintStyle + best practices
Apollo schema checkValidate against operation traffic

11. Testing Performance

ToolUse
k6 / ArtilleryLoad test against /graphql
Apollo tracingPer-resolver duration
DataLoader assertionsCount batch loads in tests

12. Snapshot Testing

Example: Snapshot

test("user response shape", async () => {
  const r = await graphql({ schema, source: USER_QUERY, variableValues: { id: "1" }, contextValue });
  expect(r.data).toMatchSnapshot();
});