Testing GraphQL APIs
Testing GraphQL APIs requires a slightly different approach than REST — since all requests go to a single endpoint, you test by sending GraphQL operation strings. The @apollo/server testing utilities and Jest make this straightforward.
1 Unit Testing Resolvers
JavaScript — Resolver Unit Tests
// resolvers.test.js
const { resolvers } = require("../src/resolvers");
describe("Query.user", () => {
it("returns a user when found", async () => {
const mockUser = { id: "1", name: "Balaji", email: "b@test.com" };
const mockDB = { User: { findById: jest.fn().mockResolvedValue(mockUser) } };
const mockCtx = { currentUser: { id: "1", role: "USER" }, db: mockDB };
const result = await resolvers.Query.user(null, { id: "1" }, mockCtx);
expect(result).toEqual(mockUser);
expect(mockDB.User.findById).toHaveBeenCalledWith("1");
});
it("throws UNAUTHENTICATED when no user in context", async () => {
const ctx = { currentUser: null };
await expect(
resolvers.Query.user(null, { id: "1" }, ctx)
).rejects.toThrow("Authentication required");
});
});
2 Integration Tests with Apollo Test Client
JavaScript — Apollo Server Integration Tests
const { ApolloServer } = require("@apollo/server");
const { typeDefs } = require("../src/schema");
const { resolvers } = require("../src/resolvers");
describe("GraphQL Integration Tests", () => {
let server;
beforeAll(async () => {
server = new ApolloServer({ typeDefs, resolvers });
await server.start();
});
afterAll(() => server.stop());
it("fetches all users", async () => {
const { body } = await server.executeOperation({
query: "{ users { id name email } }"
});
expect(body.kind).toBe("single");
expect(body.singleResult.errors).toBeUndefined();
expect(Array.isArray(body.singleResult.data.users)).toBe(true);
});
it("creates a user via mutation", async () => {
const { body } = await server.executeOperation({
query: "mutation CreateUser($input: CreateUserInput!) { createUser(input: $input) { id name } }",
variables: { input: { name: "Test User", email: "test@test.com", password: "Pass123!" } }
}, {
contextValue: { currentUser: null }
});
expect(body.singleResult.data.createUser.name).toBe("Test User");
});
it("returns UNAUTHENTICATED error for protected queries", async () => {
const { body } = await server.executeOperation(
{ query: "{ me { id name } }" },
{ contextValue: { currentUser: null } }
);
expect(body.singleResult.errors[0].extensions.code).toBe("UNAUTHENTICATED");
});
});
3 Code Challenge
Challenge: Write a complete test suite for a
Post resolver covering: listing posts (unauthenticated), creating a post (authenticated), updating a post (owner only), and deleting a post (admin only). Use mock contexts with different roles.