Skip to content

Mocking with Mock Service Worker (MSW) #1584

@baxford

Description

@baxford

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions