DEV Community

Warren Day
Warren Day

Posted on • Originally published at hashnode.com

E2E Testing with Cypress and GraphQL

You have a full-stack application and your server is running on GraphQL. It's common practice to mock out your back-end so you can test your front-end in isolation. They are separate systems after all and should be tested separately.

Until now this has been quite a difficult task. By default, cypress has poor support for mocking GraphQL servers.

This is a guide to achieving seamless GraphQL mocking in your cypress tests. With this you can easily test happy paths, edge cases and error states; all from the comfort of a single test file.

We'll be using a library specifically built for this problem.

https://github.com/warrenday/cypress-graphql-mock-network

With cypress-graphql-mock-network, you can provide your own GraphQL schema for auto-mocking, which means you only need to mock the parts you care about for each test.

Here's an example of how a test would look:

it('displays initial list of todos', () => {
  cy.mockNetworkAdd({
    Query: () => ({
      todos: () => ([
        {
          id: '1',
          title: 'Go shopping',
          completed: true,
        },
      ]),
    }),
  });

  cy.get('li')
    .eq(0)
    .contains(/Go shopping/)
    .should('exist');
});
Enter fullscreen mode Exit fullscreen mode

Here's an example of how we might mock an error state

cy.mockNetworkAdd({
  Query: () => ({
    todos: () => {
      throw new Error('Oh dear');
    },
  }),
});
Enter fullscreen mode Exit fullscreen mode

Automocking

Under the hood we're using the mocking support of graphql-tools. So you only need to supply the parts of the mock you care about for a test. The rest will be automatically filled in based on the field's type.

Let's say we have the following schema

type Todo {
  id: ID
  title: String
  completed: Boolean
}

type Query {
  todo(id: ID!): Todo
}
Enter fullscreen mode Exit fullscreen mode

In our mocks, if all we cared about was the title, we could do the following:

cy.mockNetworkAdd({
  Query: () => ({
    todo: () => ({
      title: 'I expect to be this'
    })
  }),
});
Enter fullscreen mode Exit fullscreen mode

Even if our application were to query for id, title and completed the mock would still work. We would end up receiving something like:

{
  "id": 1,
  "title": "I expect to be this",
  "completed": false
}
Enter fullscreen mode Exit fullscreen mode

Here id and completed are auto-mocked based on their type, so you can keep your tests streamlined and avoid providing a bunch of data you don't care about.

Service Workers

They'll be no monkey-patching here lad. cypress-graphql-mock-network uses the awesome https://github.com/mswjs/msw meaning real network requests are sent from your app and all mocking is inspectable in the network tab and console. This helps a ton when debugging.

The browser will continue to use the real Fetch and XHR APIs, which is much more realistic to a production environment.

Here you can see the network tab shows the request and the mocked response.
mock-network-example.png

Setup

A full setup guide is available on GitHub, which also includes a demo cypress project, so head for more details on installation and setup:
https://github.com/warrenday/cypress-graphql-mock-network

To see the demo tests in action, pull the repo then we need to do two things:

  1. Run the demo app: Change directory to /demo, install node_modules with yarn, then run yarn start

  2. Run the cypress tests: At the project root install node_modules again with yarn and then run yarn cypress

With this we should then see our the tests passing.

Screenshot 2021-07-09 at 18.02.23.png

Thanks for reading. If you have any further questions please let me know.

Top comments (4)

Collapse
 
cubo25 profile image
Jakub Vitek

I am looking for an easy way to stub graphQL any ideas or similar solution as this you provided ?

Thanks a lot !

Collapse
 
warrenday profile image
Warren Day

Hey Jakub.

What is your use-case and is there something in particular you are trying to do that this library can not help with?

Collapse
 
cyrfer profile image
John Grant

If my web app already uses a Service Worker, will MSW work?

Collapse
 
warrenday profile image
Warren Day

Hi John.

It is only possible to register a single service-worker at a time. So it would require disabling the other to use this during testing.