Does Apollo Server's createTestClient execute custom Express middleware during testing?
0 reputation · 16 Jun 2024, 19:13 UTC
0 reputation · 16 Jun 2024, 19:13 UTC
When writing integration tests for an Apollo Server schema, the goal is to verify that resolver logic works alongside any custom Express middleware (such as request‑level logging, CORS handling, or rate‑limiting) without relying on production credentials or making real network calls. The createTestClient utility from @apollo/server/testing provides an in‑process GraphQL executor, but its documentation notes that it bypasses the HTTP layer, leaving it unclear whether Express‑based middleware attached to the server instance is actually invoked during a test query.
Because the test client does not recreate the full Express request/response cycle, developers must decide whether to trust that middleware behavior is covered by these tests or to supplement them with separate middleware‑focused tests.
createTestClient invoke Express middleware registered on the Apollo Server instance?1. Does createTestClient invoke Express middleware registered on the Apollo Server instance?
No. The createTestClient helper from @apollo/server/testing constructs an ApolloServer instance and calls its executeOperation method directly. This bypasses the HTTP stack, so any Express middleware attached to the app (e.g., logging, CORS, rate‑limiting, authentication) is never executed during a test query.
2. If it does not, how can you test middleware behavior while still avoiding production credentials?
Use an integration‑style test that sends real HTTP requests through the Express app. supertest (or a similar library) can spin up the Express server in memory, mount the ApolloServer via server.applyMiddleware({ app }), and hit the GraphQL endpoint. In the test you can stub or mock external services (e.g., mock the authentication provider) so you don’t hit production credentials.
3. Are there any configuration options or patterns that enable middleware execution within the test client?
Not directly. createTestClient is intentionally HTTP‑agnostic. The only way to get middleware to run is to route the request through the Express stack, which requires a different test harness (e.g., supertest or a custom in‑process server). There are no flags on createTestClient that enable Express middleware.
const express = require('express');
const { ApolloServer } = require('@apollo/server');
const { startStandaloneServer } = require('@apollo/server/standalone');
const app = express();
// Example middleware – logging
app.use((req, res, next) => {
req.testFlag = true;
next();
});
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
server.applyMiddleware({ app });
const request = require('supertest');
it('middleware runs on GraphQL request', async () => {
const response = await request(app)
.post('/graphql')
.send({ query: '{ hello }' })
.expect(200);
// The middleware sets req.testFlag – you can assert on side‑effects
// e.g., a log entry, a header, or a mocked auth call.
});
Use libraries like nock or dependency injection to replace real credential checks or external API calls, keeping the test isolated from production systems.
createTestClient skips middleware
const { createTestClient } = require('@apollo/server/testing');
const { executeOperation } = createTestClient(server);
const result = await executeOperation({ query: '{ hello }' });
// Inspect result – no side‑effects from middleware should be present.
The executeOperation method receives a plain GraphQLRequest object; there is no req or res object, so Express hooks cannot run. This design keeps the test fast and deterministic, but it also means you must explicitly test cross‑layer concerns with a different approach.
Use createTestClient for pure resolver logic. Use supertest (or a similar HTTP client) against an Express app that mounts the ApolloServer if you need to validate middleware, CORS, or authentication behavior.
Use comments to ask for clarification. Post a solution as an answer.
29,275 reputation · 16 Jun 2024, 23:45 UTC
Because createTestClient invokes ApolloServer.executeOperation directly, it never touches the Express router, so any middleware registered with expressMiddleware (or the older applyMiddleware) is skipped regardless of configuration.
To verify middleware behavior while still avoiding real credentials, mount the Apollo Server on an Express app with expressMiddleware and use a library like supertest to send HTTP requests to /graphql. This exercises the full middleware chain while letting you mock external services in the test.