-
-
Notifications
You must be signed in to change notification settings - Fork 33
Description
Hi, first of all, thanks for this amazing library, I find it useful both serverside and in React apps!
This is my first post here, so please let me know if I can provide more info or code samples.
I have been looking into ways of mocking gqty in test cases, and have tried a few different options.
My first attempt was to mock the gqty generated client with Jest and then replace the implementations of query / mutation etc.
jest.mock('../src/gqty', () => ({
This works to some extent but my tests aren't as real-world as I would like them to be.
My latest efforts are to use Mock Service Worker, which is partially working for me, with the following conditions:
- gqty uses anonymous operations so MSW graphql.query an graphql.mutation options are not available, instead I had to use graphql.operation.. See https://mswjs.io/docs/getting-started/mocks/graphql-api
- gqty appears to use aliases (I think for caching purposes) when building the graphql commands, so the graphql.operation needs to run regexes on the query and match preconfigured operation names.
- jsonb fields are also aliased within the query (I guess also for caching purposes), so these would need some regex/pattern matching to resolve (I haven't done this yet)
The following code addresses the first two points above but not the third. I think it would be possible to address the third but it feels quite complex, and I am wondering if there might be another way to solve this.
export const MOCK_GRAPHQL_API = 'http://test-graphql.api/'
jest.mock('next/config', () => () => ({
publicRuntimeConfig: {
publicGraphqlUrl: MOCK_GRAPHQL_API
}
}))
import { SetupServer, setupServer } from "msw/node";
import { RequestHandler, graphql } from "msw";
const mockGraphqlAPI = graphql.link(MOCK_GRAPHQL_API);
export interface MockGraphqlResponse {
type: string;
operation: string;
response: object | object[];
}
let server: SetupServer;
export const mockAPI = (mockResponses: MockGraphqlResponse[]) => {
const handlers: Array<RequestHandler> = [
mockGraphqlAPI.operation(async (req, res, ctx) => {
const m = await req.json()
// console.log(m)
const matchedOp = mockResponses.reduce((acc, {type, operation, response}) => {
// It appears that gqty uses dynamic aliases for mutations/queries.
// So we use a regex to find the alias and return the given data for the alias
const typeRe = new RegExp('^(' + type + ')\\(');
const typeMatches = m.query.match(typeRe)
const operationRe = new RegExp('\\{(' + operation + '_.*)\:' + operation + '\\(');
const opMatches = m.query.match(operationRe)
if (typeMatches && opMatches) {
const alias = opMatches[1];
const data = {} as any;
data[alias] = response;
acc = { data }
}
return acc;
}, null as any)
if (matchedOp?.data) {
return res(ctx.data(matchedOp.data));
} else {
return;
}
})
];
server = setupServer(...handlers);
server.listen({
onUnhandledRequest: 'error',
})
}
export const closeMockServer = () => {
server?.close();
}
The above can then be used in test cases as follows:
//Define mock responses for the Graphql operations.
const mockAPIResponses = [{
type: 'query',
operation: 'user_by_pk',
response: {
id: 'userId123',
name: 'Test User',
email: '[email protected]',
}
}];
beforeEach(() => {
mockAPI(mockAPIResponses);
})
afterEach(() => {
closeMockServer();
})
This allows my react test cases to fully test the gqty code within the rendering, however it feels a little clunky.
I'm wondering if anyone here knows of a better way of using MSW for this type of testing?
If it was possible to override the aliasing or switch it off in the test cases it may simplify things.