Msw: Not interecepting GraphQL request ONLY in the test

Created on 24 Nov 2020  路  9Comments  路  Source: mswjs/msw

Environment

| Name | Version |
| ---- | ------- |
| msw | 0.21.3 |
| node | 14.15.0 |
| OS | MacOS 10.15.7 (19H2) |
| Relay Hooks | 3.5.2 |
| Jest | 24.9.0 |

Request handlers

// Example of declaration. Provide your code here.
import { setupServer } from 'msw/node'
import { graphql } from 'msw'

const server = setupServer(
  graphql.query('SponsorAddressesQuery', (req, res, ctx) => {
    return res(
      ctx.data({
        "sponsor": {
          "__typename": "CompanySponsor",
          "addresses": [
            {
              "id": "126cf883-ca26-4b5e-ad7f-4389a0faaf98",
              "number": "1231",
              "city": "S脙O PAULO",
              "state": "SP",
              "neighborhood": "PINHEIROS",
              "zipCode": "05404013",
              "additionalInfo": "1114",
              "street": "RUA ARTUR DE AZEVEDO 123"
            }
          ],
          "id": "04a427b5-172e-42b6-8638-7bc0f246cc7c"
        }
      })
    );
  })
)

server.listen()

Actual request

I'm dealing with GraphQL using Relay

// Example of making a request. Provide your code here.

// my query file
import graphql from 'babel-plugin-relay/macro';

export const getQuery = () => {
  return graphql`
    query SponsorAddressesQuery($id: ID!) {
      addresses { ... }
    }
  `;
};


// how do I use it
import { useQuery } from 'relay-hooks';

useQuery(getQuery(), { id: '123' });

Current behavior

Currently my setup is working on the browser, but it seems not intercepting during my Jest test.
It's returning nothing in the test, even errors.

Expected behavior

Expect to return mocked data.

bug discussion node

All 9 comments

Hey, @lai-caju. Thanks for reporting this.

Please, could you elaborate some more:

  1. What testing framework do you use?
  2. How do you integrate your setupServer module with your testing framework? That module needs to execute as a part of your tests.

@kettanaito , sure:

  1. I'm using @testing-library/[email protected].
  2. I'm turning the server on in the beforeAll like:
import { server } from '/mocks/server';

beforeAll(() => server.listen());

afterAll(() => server.close());

test('my test here', () => { .... });

And my server.js looks like this:

import { setupServer } from 'msw/node';
import handlers from './handlers';

export { rest, graphql } from 'msw';
export const server = setupServer(...handlers);

Could you provide your jest config please?

The weird thing is, I have some REST endpoint in the system and I'm able to mock REST endpoint in tests, but GraphQL are not working

@aganglada , my jest config is this:

const { pathsToModuleNameMapper } = require('ts-jest/utils')
const { compilerOptions } = require('./tsconfig')

module.exports = {
  preset: 'ts-jest',
  roots: ['<rootDir>'],
  modulePaths: ['<rootDir>'],
  moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths),
  testEnvironment: 'node',
};

This is my src/setupTest.js:

import '@testing-library/jest-dom/extend-expect';
import MutationObserver from '@sheerun/mutationobserver-shim'
window.MutationObserver = MutationObserver;

I have a similar problem with Apollo, it usually happens when I don't provide all the query fields in the mock. E.g. say you request this data in your query:

query product {
   id
   type
   price
   color
}

In your graphql handler you have to mock the data contain all the fields from the above:

graphql.query('product', (_, res, ctx) =>
    res(
      ctx.data({
        product: {
          id: 1,
          type: 'basic',
          price: 100,
          color: 'red',
        },
      }),
    ),
  ),

If just any of those fields is missing, msw won't return anything, staying silent.
@kettanaito I'd prefer to have some error output in this case. It will save me time debugging why there's no mocked response in my test.

@eugeneoshepkov I think that is Apollo's behavior. MSW will set any given ctx.data as a GraphQL response payload. There's no query-compliance validation whatsoever. When a GraphQL client receives a partial response payload according to a query it's up to it to handle this scenario. It's a _server_'s responsibility to validate a payload against a query, as the server produces errors that may contain useful hints alike "cannot return null for non-nullable "price" field". As to why you receive an empty payload that I'm not sure, you should get exactly what you specified in the response resolver.

You can type guard your mocks if you are using TypeScript and have GraphQL operation types generated. graphql.* request handlers accept generic types that will validate your returned payload on build time, alerting you if you're responding with a partial payload. Take a look at the GraphQL request handlers with TypeScript usage example.

@lai-caju, If other request handlers from the same setup work that may imply that either a GraphQL handler doesn't match an actual request or an actual request is somehow not considered to be GraphQL by MSW. Let's narrow down both of these possibilities.

Using transparent handler

Try attaching a transparent handler to your mock definition _before_ you have your graphql.* handler. This will catch _any_ requests and you can inspect if your GraphQL request is there.

import { rest } from 'msw'

setupServer(
  // Use the right REST handler: rest.post or rest.get, depending on how
  // your GraphQL request is issued (both ways are allowed, check what you have).
  rest.post('*', (req) => console.log(req.href.url),

  // Your current handler after.
  graphql.query(...)
)

If you see the request URL logged out when the request happens鈥攇ood. Dive deeper and inspect more reqproperties, such as req.headers, req.body, req.url.searchParams. Post their values in this thread. Be extra cautious to use a proper REST handler according to how your request is made (GraphQL requests still partially follow REST specification in terms of methods, headers, body, etc.).

  • If you issue a request as a GET request, look up the query definition in req.url.searchParams.
  • If you issue a request as a POST request, look up the query definition in req.body.

Thanks @kettanaito for support! I'll close this issue, since that we figured out the problem was in my application.
It wasn't about MSW or Relay, my application was having some exception before the request.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dashed picture dashed  路  3Comments

dashed picture dashed  路  4Comments

baker-travis picture baker-travis  路  3Comments

luistak picture luistak  路  3Comments

danielstreit picture danielstreit  路  3Comments