Hi @dkuc
I hope you are doing good. I’m writing this to you as I’m struck with Apollo Client testing at React. We usually create a express server to run as bff mock for the UI to load mock data to develop UI on top of it locally. One of our UIs use Apollo client to invoke the backend ‘/graphql’ endpoint served on POST for both queries and mutation. While trying to mock the API behavior from the UI side, we are unable to serve the request based on the body passed to the graphql endpoint.
I tried making use of MSW and it is not even intercepting the graphql endpoint calls invoked by the Apollo client locally. Also, when i try to mock via rest by matching the endpoint, I see that the request is served for the /graphql endpoint with the mock data, but we couldnt capture the body of the request.
The idea here is to conditionally serve a response to the /graphql endpoint based on the request body i.e. Query or Mutation. Any suggestions on how to achieve this?
Note: Our GraphQL back end is based on Spring Boot and it only exposes the endpoint as POST.
Sample Express Code:
/* eslint-disable import/no-extraneous-dependencies */
const express = require('express')
const { graphql, rest } = require('msw')
const { createMiddleware } = require('@mswjs/http-middleware')
const { verify } = require('njwt')
const fs = require('fs')
const config = require('../config')
// import { readFileSync } from 'fs'
// import { bff, bffMock } from '../config'
const secret = 'shhhhhhhh'
const jwtRegEx = /^[bB]earer\s+([-\w-]+.[-\w]+.[-\w]+)$/
const graphApi = graphql.link('/graphql')
const query = `
query GetTasksByAssignee($assignee: String!) {
tasksByAssignee(assignee: $assignee) {
name
creationDate
dueDate
}
}
`
const getJwtFromAuthHeader = req => {
const authorizationHeader = req.header('Authorization')
const match = jwtRegEx.exec(authorizationHeader || '')
return match && (match[1] || '')
}
const buildMswApp = ({ mockFilename, secure }) => {
const app = express()
// Register json server's middleware
app.use(
createMiddleware(
rest.post('/graphql', (req, res, ctx) => {
console.log(req)
return res(
ctx.json({
data: {
tasksByAssignee: [
{
id: 209757,
name: 'CKARTH 1 login metadata',
creationDate: '2011-05-23T04:22:55.000+00:00',
dueDate: '2011-05-25T04:22:55.000+00:00'
}
]
}
})
)
}),
graphql.operation(async (req, res, ctx) => {
const { query } = await req.json()
console.log(query)
return res(
ctx.data({
tasksByAssignee: [
{
id: 209757,
name: 'CKARTH 1 login metadata',
creationDate: '2011-05-23T04:22:55.000+00:00',
dueDate: '2011-05-25T04:22:55.000+00:00'
}
]
})
)
}),
graphApi.query('GetTasksByAssignee', (req, res, ctx) => {
const { assignee } = req.variables
console.log('aa gya')
return res(
ctx.data({
tasksByAssignee: [
{
id: 209757,
name: 'CKARTH 1 login metadata',
creationDate: '2011-05-23T04:22:55.000+00:00',
dueDate: '2011-05-25T04:22:55.000+00:00'
}
]
})
)
}),
graphApi.mutation('completeTask', (req, res, ctx) => {
const { assignee } = req.variables
console.log('aa gya')
return res(
ctx.data({
tasksByAssignee: [
{
id: 209757,
name: 'CKARTH 1 login metadata',
creationDate: '2011-05-23T04:22:55.000+00:00',
dueDate: '2011-05-25T04:22:55.000+00:00'
}
]
})
)
})
)
)
// Configure response with correct API version
app.use((req, res, next) => {
const jwt = getJwtFromAuthHeader(req)
if (secure) {
verify(jwt, secret, err => {
if (err) {
res.status(401)
res.send('Unauthorized')
} else {
console.log('heelo')
res.header('Content-Type', config.bff.api.contentType)
}
next()
})
} else {
res.header('Content-Type', config.bff.api.contentType)
next()
}
})
// Register any custom endpoints here before the jsonServer router is registered.
// You can modify the 'mock.json' file and the changes will be reflected in the mock server.
// app.use('/custom', customMiddleware())
// app.post('/graphql', (req, res) => {
// console.log(req.query.query)
// const mockData = JSON.parse(readFileSync(mockFilename, 'utf8'))
// res.status(200)
// res.send(mockData.tasks)
// })
// Register router
// app.use(bffMock.api.path, router)
return app
}
module.exports = buildMswApp
In the above code, only the rest handler is intercepting the graphql endpoint, but cannot capture the body in the res variable. Whereas none of the graphql handlers intercept the graphql invocation and always result in 404.