mswjs / msw

Industry standard API mocking for JavaScript.
https://mswjs.io
MIT License
15.87k stars 516 forks source link

Using fragment incorporation breaks the mocked response in GraphQL #630

Closed gabrielhpugliese closed 3 years ago

gabrielhpugliese commented 3 years ago

Describe the bug

I am trying to mock Github's public GraphQL API. I am trying to fetch public repositories. Whenever I try to incorporate a fragment on the query, something happens (still trying to understand) and the response is not properly returned.

Environment

Please also provide your browser version.

Chrome Version 88.0.4324.96 (Official Build) (x86_64)

To Reproduce

Steps to reproduce the behavior:

  1. Go to the Github' API Explorer: https://docs.github.com/en/graphql/overview/explorer
  2. Do this query:
    {
    search(query: "react", type: REPOSITORY, first: 10) {
    repositoryCount
    edges {
      node {
        ... on Repository {
          id
        }
      }
    }
    }
    }
  3. Copy and paste the response to your mock handler (file is in the end)
  4. Query your mock handler with only the first line to see if everything works:
    query getPublicRepositories {
    search(query: "react", type: REPOSITORY, first: 10)
    }
  5. It works! Nice! You can see everything is returned.
  6. Now change the query. Make the same "subquery" as you have done in the explorer:
    query getPublicRepositories {
    search(query: "react", type: REPOSITORY, first: 10) {
      repositoryCount
      edges {
        node {
          ... on Repository {
            id
          }
        }
      }
    }
    }
  7. Does not work anymore. The response is something like this:
    {
    "search": {
    "repositoryCount": 1914858,
    "edges": [
      {
        "node": {}
      },
      {
        "node": {}
      },
      {
        "node": {}
      },
      {
        "node": {}
      },
      {
        "node": {}
      },
      {
        "node": {}
      },
      {
        "node": {}
      },
      {
        "node": {}
      },
      {
        "node": {}
      },
      {
        "node": {}
      }
    ]
    }
    }

Expected behavior

I expect that it would just work as when I do not use the incorporation. Works fine if I want to mock anything that does not use incorporation.

Screenshots

Not screenshot but a payload I am using to mock:

import {graphql, setupWorker} from 'msw';

const handlers = [
  graphql.query('getPublicRepositories', (req, res, ctx) => {
    return res(
      ctx.data({
        search: {
          repositoryCount: 1914858,
          edges: [
            {
              node: {
                id: 'MDEwOlJlcG9zaXRvcnkxMDI3MDI1MA==',
                name: 'react',
                description:
                  'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
                stargazerCount: 164492,
                url: 'https://github.com/facebook/react',
                updatedAt: '2021-03-03T09:27:39Z',
                owner: {
                  id: 'MDEyOk9yZ2FuaXphdGlvbjY5NjMx',
                  login: 'facebook',
                },
                repositoryTopics: {
                  nodes: [
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzQwNjE0OTY=',
                      topic: {
                        id: 'MDU6VG9waWNqYXZhc2NyaXB0',
                        name: 'javascript',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzQwNjE0OTg=',
                      topic: {
                        id: 'MDU6VG9waWNyZWFjdA==',
                        name: 'react',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzQwNjE1MDI=',
                      topic: {
                        id: 'MDU6VG9waWNmcm9udGVuZA==',
                        name: 'frontend',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzQwNjE1MTk=',
                      topic: {
                        id: 'MDU6VG9waWNkZWNsYXJhdGl2ZQ==',
                        name: 'declarative',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzQwNjE1MjE=',
                      topic: {
                        id: 'MDU6VG9waWN1aQ==',
                        name: 'ui',
                      },
                    },
                  ],
                },
                primaryLanguage: {
                  id: 'MDg6TGFuZ3VhZ2UxNDA=',
                  name: 'JavaScript',
                  color: '#f1e05a',
                },
                licenseInfo: {
                  id: 'MDc6TGljZW5zZTEz',
                  name: 'MIT License',
                },
              },
            },
            {
              node: {
                id: 'MDEwOlJlcG9zaXRvcnkxMzU3ODYwOTM=',
                name: 'react',
                description:
                  'Cheatsheets for experienced React developers getting started with TypeScript',
                stargazerCount: 22454,
                url: 'https://github.com/typescript-cheatsheets/react',
                updatedAt: '2021-03-03T09:13:59Z',
                owner: {
                  id: 'MDEyOk9yZ2FuaXphdGlvbjUwMTg4MjY0',
                  login: 'typescript-cheatsheets',
                },
                repositoryTopics: {
                  nodes: [
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzE4ODEyNDMw',
                      topic: {
                        id: 'MDU6VG9waWN0eXBlc2NyaXB0',
                        name: 'typescript',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzE4ODEyNDMx',
                      topic: {
                        id: 'MDU6VG9waWN0eXBlc2NyaXB0LXBsYXlncm91bmQ=',
                        name: 'typescript-playground',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzE4ODEyNDMy',
                      topic: {
                        id: 'MDU6VG9waWNyZWZlcmVuY2U=',
                        name: 'reference',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzE4ODEyNDMz',
                      topic: {
                        id: 'MDU6VG9waWN0cw==',
                        name: 'ts',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzE4ODEyNDM0',
                      topic: {
                        id: 'MDU6VG9waWNjaGVhdHNoZWV0',
                        name: 'cheatsheet',
                      },
                    },
                  ],
                },
                primaryLanguage: {
                  id: 'MDg6TGFuZ3VhZ2UxNDA=',
                  name: 'JavaScript',
                  color: '#f1e05a',
                },
                licenseInfo: {
                  id: 'MDc6TGljZW5zZTEz',
                  name: 'MIT License',
                },
              },
            },
            {
              node: {
                id: 'MDEwOlJlcG9zaXRvcnk3NTM5NjU3NQ==',
                name: 'react',
                description:
                  ' React+webpack+redux+ant design+axios+less全家桶后台管理框架',
                stargazerCount: 4072,
                url: 'https://github.com/duxianwei520/react',
                updatedAt: '2021-03-03T08:14:12Z',
                owner: {
                  id: 'MDQ6VXNlcjMyNDk2NTM=',
                  login: 'duxianwei520',
                },
                repositoryTopics: {
                  nodes: [
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzcwOTg4Mw==',
                      topic: {
                        id: 'MDU6VG9waWNyZWFjdA==',
                        name: 'react',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzcwOTg4Ng==',
                      topic: {
                        id: 'MDU6VG9waWN3ZWJwYWNr',
                        name: 'webpack',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzcwOTg4OA==',
                      topic: {
                        id: 'MDU6VG9waWNhbnRk',
                        name: 'antd',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzcwOTg5NA==',
                      topic: {
                        id: 'MDU6VG9waWNlczY=',
                        name: 'es6',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzcwOTg5Ng==',
                      topic: {
                        id: 'MDU6VG9waWNyZWR1eA==',
                        name: 'redux',
                      },
                    },
                  ],
                },
                primaryLanguage: {
                  id: 'MDg6TGFuZ3VhZ2UxNDA=',
                  name: 'JavaScript',
                  color: '#f1e05a',
                },
                licenseInfo: {
                  id: 'MDc6TGljZW5zZTEz',
                  name: 'MIT License',
                },
              },
            },
            {
              node: {
                id: 'MDEwOlJlcG9zaXRvcnk5MDc1OTkzMA==',
                name: 'react',
                description: 'React docs in Chinese | React 中文文档翻译',
                stargazerCount: 994,
                url: 'https://github.com/discountry/react',
                updatedAt: '2021-03-03T06:57:02Z',
                owner: {
                  id: 'MDQ6VXNlcjQ1MDcxMDE=',
                  login: 'discountry',
                },
                repositoryTopics: {
                  nodes: [
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzIzODE2NTc=',
                      topic: {
                        id: 'MDU6VG9waWNyZWFjdA==',
                        name: 'react',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzIzODE2NTg=',
                      topic: {
                        id: 'MDU6VG9waWNkb2Nz',
                        name: 'docs',
                      },
                    },
                  ],
                },
                primaryLanguage: {
                  id: 'MDg6TGFuZ3VhZ2UxNDA=',
                  name: 'JavaScript',
                  color: '#f1e05a',
                },
                licenseInfo: {
                  id: 'MDc6TGljZW5zZTI1',
                  name: 'Creative Commons Attribution 4.0 International',
                },
              },
            },
            {
              node: {
                id: 'MDEwOlJlcG9zaXRvcnk3MjYyODI4NQ==',
                name: 'react',
                description: '京东首页构建',
                stargazerCount: 708,
                url: 'https://github.com/Cathy0807/react',
                updatedAt: '2021-03-03T03:33:32Z',
                owner: {
                  id: 'MDQ6VXNlcjIwNjUzNjQz',
                  login: 'Cathy0807',
                },
                repositoryTopics: {
                  nodes: [],
                },
                primaryLanguage: {
                  id: 'MDg6TGFuZ3VhZ2UxNDA=',
                  name: 'JavaScript',
                  color: '#f1e05a',
                },
                licenseInfo: null,
              },
            },
            {
              node: {
                id: 'MDEwOlJlcG9zaXRvcnk3NzUxMzQxOQ==',
                name: 'react',
                description: '基于react的企业后台管理开发框架',
                stargazerCount: 799,
                url: 'https://github.com/react-redux-antd-es6/react',
                updatedAt: '2021-03-03T08:22:19Z',
                owner: {
                  id: 'MDEyOk9yZ2FuaXphdGlvbjI0ODA1MTQy',
                  login: 'react-redux-antd-es6',
                },
                repositoryTopics: {
                  nodes: [
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzk0NzUwNA==',
                      topic: {
                        id: 'MDU6VG9waWNyZWFjdA==',
                        name: 'react',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzk0NzUwNg==',
                      topic: {
                        id: 'MDU6VG9waWNhbnRk',
                        name: 'antd',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzk0NzUwNw==',
                      topic: {
                        id: 'MDU6VG9waWN3ZWJwYWNr',
                        name: 'webpack',
                      },
                    },
                  ],
                },
                primaryLanguage: {
                  id: 'MDg6TGFuZ3VhZ2UxNDA=',
                  name: 'JavaScript',
                  color: '#f1e05a',
                },
                licenseInfo: {
                  id: 'MDc6TGljZW5zZTEz',
                  name: 'MIT License',
                },
              },
            },
            {
              node: {
                id: 'MDEwOlJlcG9zaXRvcnk5MzUwMzU0NQ==',
                name: 'React',
                description:
                  'This repository contains all the material for the HackYourFuture module "React.js: Building dynamic UIs with modern JavaScript"',
                stargazerCount: 119,
                url: 'https://github.com/HackYourFuture/React',
                updatedAt: '2021-03-03T01:45:57Z',
                owner: {
                  id: 'MDEyOk9yZ2FuaXphdGlvbjIwODU4NTY4',
                  login: 'HackYourFuture',
                },
                repositoryTopics: {
                  nodes: [
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzY0OTA3MjI=',
                      topic: {
                        id: 'MDU6VG9waWNyZWFjdA==',
                        name: 'react',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzY0OTA3MjM=',
                      topic: {
                        id: 'MDU6VG9waWNtb2J4',
                        name: 'mobx',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzY0OTA3MjQ=',
                      topic: {
                        id: 'MDU6VG9waWNoeWY=',
                        name: 'hyf',
                      },
                    },
                  ],
                },
                primaryLanguage: null,
                licenseInfo: null,
              },
            },
            {
              node: {
                id: 'MDEwOlJlcG9zaXRvcnkyNDgyOTUxNzA=',
                name: 'react',
                description: 'Modern and minimalist React UI library.',
                stargazerCount: 1541,
                url: 'https://github.com/geist-org/react',
                updatedAt: '2021-03-03T00:10:27Z',
                owner: {
                  id: 'MDEyOk9yZ2FuaXphdGlvbjY5ODQ4NzUy',
                  login: 'geist-org',
                },
                repositoryTopics: {
                  nodes: [
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzE2MTI0NDEy',
                      topic: {
                        id: 'MDU6VG9waWNyZWFjdC1jb21wb25lbnRz',
                        name: 'react-components',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzE2MTI0NDE1',
                      topic: {
                        id: 'MDU6VG9waWNyZWFjdA==',
                        name: 'react',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzE4MjA1OTE5',
                      topic: {
                        id: 'MDU6VG9waWNnZWlzdA==',
                        name: 'geist',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzE4MjA4NTEw',
                      topic: {
                        id: 'MDU6VG9waWNkZXNpZ24tc3lzdGVt',
                        name: 'design-system',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzE4MjA4NTE1',
                      topic: {
                        id: 'MDU6VG9waWNnZWlzdC11aQ==',
                        name: 'geist-ui',
                      },
                    },
                  ],
                },
                primaryLanguage: {
                  id: 'MDg6TGFuZ3VhZ2UyODc=',
                  name: 'TypeScript',
                  color: '#2b7489',
                },
                licenseInfo: {
                  id: 'MDc6TGljZW5zZTEz',
                  name: 'MIT License',
                },
              },
            },
            {
              node: {
                id: 'MDEwOlJlcG9zaXRvcnkzNjA2NjI0',
                name: 'ReactiveCocoa',
                description:
                  'Cocoa framework and Obj-C dynamism bindings for ReactiveSwift.',
                stargazerCount: 19946,
                url: 'https://github.com/ReactiveCocoa/ReactiveCocoa',
                updatedAt: '2021-03-03T08:22:19Z',
                owner: {
                  id: 'MDEyOk9yZ2FuaXphdGlvbjM0MjI5Nzc=',
                  login: 'ReactiveCocoa',
                },
                repositoryTopics: {
                  nodes: [
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzMwODcyMQ==',
                      topic: {
                        id: 'MDU6VG9waWNyZWFjdGl2ZXN3aWZ0',
                        name: 'reactiveswift',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzMwODcyMg==',
                      topic: {
                        id: 'MDU6VG9waWNyZWFjdGl2ZWNvY29h',
                        name: 'reactivecocoa',
                      },
                    },
                    {
                      id: 'MDE1OlJlcG9zaXRvcnlUb3BpYzM4NjgzNw==',
                      topic: {
                        id: 'MDU6VG9waWNzd2lmdA==',
                        name: 'swift',
                      },
                    },
                  ],
                },
                primaryLanguage: {
                  id: 'MDg6TGFuZ3VhZ2UzNzE=',
                  name: 'Swift',
                  color: '#ffac45',
                },
                licenseInfo: {
                  id: 'MDc6TGljZW5zZTA=',
                  name: 'Other',
                },
              },
            },
            {
              node: {
                id: 'MDEwOlJlcG9zaXRvcnkyOTAyODc3NQ==',
                name: 'react-native',
                description: 'A framework for building native apps with React.',
                stargazerCount: 93666,
                url: 'https://github.com/facebook/react-native',
                updatedAt: '2021-03-03T09:11:11Z',
                owner: {
                  id: 'MDEyOk9yZ2FuaXphdGlvbjY5NjMx',
                  login: 'facebook',
                },
                repositoryTopics: {
                  nodes: [],
                },
                primaryLanguage: {
                  id: 'MDg6TGFuZ3VhZ2UxNDA=',
                  name: 'JavaScript',
                  color: '#f1e05a',
                },
                licenseInfo: {
                  id: 'MDc6TGljZW5zZTA=',
                  name: 'Other',
                },
              },
            },
          ],
        },
      }),
    );
  }),
];

export const worker = setupWorker(...handlers);
netcoding87 commented 3 years ago

Any updates here? Unfortunately I recently run into the same issue...

kettanaito commented 3 years ago

Hey, @gabrielhpugliese. Thanks for reporting this.

Could you please share the code where you make an actual GraphQL query?

I'm putting this into a test case and it passes without issues. This implies the problem may be either in how the actual query is made, or how the GraphQL client is used. I can elaborate more once you provide more info. Thanks.

gabrielhpugliese commented 3 years ago

Hi @kettanaito ,

The query I've put on this original post is this one: https://github.com/gabrielhpugliese/MediaMarktSaturn/blob/b2061e1c2677853f8ca614ee79fe6acafd9622a7/src/lib/queries.ts#L23

If you take a closer look into the file and the switch case in the end of the file, you will see I return queries for prod and test envs. If you compare the same query for the test env you will see that I rip off a big part of the query in order to run it. It kinda works but it's a bit hacky. It does not work on the browser == dev env. The same query for dev is in this line: https://github.com/gabrielhpugliese/MediaMarktSaturn/blob/b2061e1c2677853f8ca614ee79fe6acafd9622a7/src/lib/queries.ts#L180

kettanaito commented 3 years ago

Thank you for the follow-up. Queries are good, the main interest goes to which GraphQL client you're u sing. It appears that's Apollo. There's a nuance with Apollo where it expects the data you return to have the __typename property describing the type of the data. Apollo is likely to strip the data that doesn't have the __typename property, that's why this scenario works fine in isolation but results in empty nodes with queried with Apollo.

We mention this in the GraphQL integration, but it's not the most evident issue to catch.

I don't see any explicit __typename when inspecting the GitHub Explorer's response, so I may only suggest adding this to your nodes in the mocked data:

{
  node: {
    __typename: 'Repository',
    // ...the rest of properties you have (i.e. "id", "description", etc.)
  }
}

Could you please try this and let me know?

netcoding87 commented 3 years ago

Hi @kettanaito, thanks a lot for that hint. Indeed with adding the __typename it works for me 👍

Note: In my project I'm using Typescript and created the types for my graphql queries and mutation with the graphql-codegen . Initially I configured it to skip the typename propery wherefore in the handler this property was not offered / allowed. Now the typenames are not skipped and when setting them correctly all requests are resolved as expected 👍

gabrielhpugliese commented 3 years ago

Many thanks @kettanaito and @netcoding87 . I will try it whenever possible, right now I am really busy! But thanks again!