Answer to the Core Questions
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.
Practical Steps to Test Middleware
- Set up Express and ApolloServer
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 });
- Write a supertest integration test
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.
});
- Mock external dependencies
Use libraries like nock or dependency injection to replace real credential checks or external API calls, keeping the test isolated from production systems.
- Optional: Verify that
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.
Why Middleware Is Skipped
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.
Key Takeaway
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.