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');
});
Here's an example of how we might mock an error state
cy.mockNetworkAdd({
Query: () => ({
todos: () => {
throw new Error('Oh dear');
},
}),
});
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
}
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'
})
}),
});
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
}
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.
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:
Run the demo app: Change directory to /demo, install node_modules with
yarn
, then runyarn start
Run the cypress tests: At the project root install node_modules again with
yarn
and then runyarn cypress
With this we should then see our the tests passing.
Thanks for reading. If you have any further questions please let me know.
Top comments (4)
If my web app already uses a Service Worker, will MSW work?
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.
I am looking for an easy way to stub graphQL any ideas or similar solution as this you provided ?
Thanks a lot !
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?