Labs ICT
Pro Login

Testing GraphQL APIs

Testing GraphQL APIs

Testing is crucial for reliable GraphQL APIs. You need to test your schema, resolvers, and client queries. Let's explore different testing strategies.

Testing Resolvers

The simplest approach is testing resolver functions directly:

const { createTestClient } = require('apollo-server-testing');
const { ApolloServer } = require('@apollo/server');
const typeDefs = require('./schema');
const resolvers = require('./resolvers');
const db = require('./database');

describe('User Resolvers', () => {
  let server;
  
  beforeEach(() => {
    server = new ApolloServer({
      typeDefs,
      resolvers,
      context: () => ({ db }),
    });
  });
  
  it('fetches a user by id', async () => {
    const { query } = createTestClient(server);
    
    const res = await query({
      query: `
        query GetUser($id: ID!) {
          user(id: $id) {
            name
            email
          }
        }
      `,
      variables: { id: '1' },
    });
    
    expect(res.data.user).toBeDefined();
    expect(res.data.user.name).toBe('Alice');
  });
  
  it('returns null for non-existent user', async () => {
    const { query } = createTestClient(server);
    
    const res = await query({
      query: `
        query GetUser($id: ID!) {
          user(id: $id) {
            name
          }
        }
      `,
      variables: { id: '999' },
    });
    
    expect(res.data.user).toBeNull();
  });
});

Test client lets you execute queries against your server without starting it.

Testing Mutations

Testing mutations follows the same pattern but uses the mutate function:

describe('User Mutations', () => {
  it('creates a new user', async () => {
    const { mutate } = createTestClient(server);
    
    const res = await mutate({
      mutation: `
        mutation CreateUser($input: CreateUserInput!) {
          createUser(input: $input) {
            id
            name
            email
          }
        }
      `,
      variables: {
        input: {
          name: 'Test User',
          email: 'test@example.com',
        },
      },
    });
    
    expect(res.data.createUser).toBeDefined();
    expect(res.data.createUser.name).toBe('Test User');
  });
  
  it('validates required fields', async () => {
    const { mutate } = createTestClient(server);
    
    const res = await mutate({
      mutation: `
        mutation CreateUser($input: CreateUserInput!) {
          createUser(input: $input) {
            id
          }
        }
      `,
      variables: {
        input: { name: '' }, // Missing email
      },
    });
    
    expect(res.errors).toBeDefined();
    expect(res.errors[0].message).toContain('email');
  });
});

Always test both success and error cases for mutations.

Integration Testing

Integration tests verify your entire stack works together:

const request = require('supertest');
const { startServer } = require('./server');

describe('GraphQL API Integration', () => {
  let server;
  let httpServer;
  
  beforeAll(async () => {
    const result = await startServer();
    httpServer = result.httpServer;
  });
  
  afterAll(async () => {
    await httpServer.close();
  });
  
  it('responds to health check', async () => {
    const res = await request(httpServer)
      .post('/graphql')
      .send({ query: '{ __typename }' });
    
    expect(res.status).toBe(200);
    expect(res.body.data.__typename).toBe('Query');
  });
  
  it('returns user data', async () => {
    const res = await request(httpServer)
      .post('/graphql')
      .send({
        query: `
          query {
            user(id: "1") {
              name
            }
          }
        `,
      });
    
    expect(res.status).toBe(200);
    expect(res.body.data.user).toBeDefined();
  });
});

Integration tests catch issues that unit tests might miss.

Testing Best Practices

Test the schema: Use introspection to verify your schema is valid.

Mock external services: Don't rely on real databases in tests.

Test error cases: Make sure errors are handled gracefully.

Use test data: Create consistent test fixtures for reliable results.

// Schema validation test
it('validates the schema', () => {
  const { validateSchema } = require('graphql');
  const errors = validateSchema(schema);
  expect(errors).toHaveLength(0);
});

// Mock database for tests
const mockDb = {
  users: [
    { id: '1', name: 'Test User', email: 'test@example.com' },
  ],
  posts: [],
};