Closed
Description
Here is a potential solution to stubbing graphql requests in Cypress
Caveats
- the requests cannot be
waited
on, but they do return promises that resolve immediately so it shouldn't be an issue in practice - a new
visit
is required to set or change a stub, so this can have a negative performance impact on the tests - assumes your app is using
fetch
but can probably be modified to work forxhr
- assumes you are using Cypress v0.20.x (I think)
- does not provide any error handling
Details
1. Create a Cypress Command
to make life easier
/*
* Create a command named `visitStubbed` that wraps the normal `cy.visit`. It
* takes the url as the first parameter and * an object with your graphql
* request stubs. Each key of the object must match the `operationName` of the
* graphql request to be stubbed and each value is an object containing the
* stubbed graphql response.
*
* Ex.
* ```
* cy.visitStubbed('/home', {
* fetchWidgets: {
* data: {
* widgets: [{
* id: 1,
* name: 'Cool Widget',
* __typename: 'Widget',
* //...
* }]
* }
* }
* })
* ```
*/
// import the function from the following step (optional)
import { runQuery } from '../support/graphql'
Cypress.Commands.add('visitStubbed', function(url, operations = {}) {
cy.visit(url, {
onBeforeLoad: win => {
cy
// stub `fetch`
.stub(win, 'fetch')
// your graphql endpoint
.withArgs('/graphql')
// call our stub
.callsFake(serverStub)
},
})
function serverStub(_, req) {
// parse the request
const { operationName, query, variables } = JSON.parse(req.body)
// return the stub if it was provided
const resultStub = operations[operationName]
if (resultStub) {
return Promise.resolve(responseStub(resultStub))
}
// else {
// return {}
// }
// If you want, fallback to default mock data if stub for operation is not specified (optional)
return runQuery(query, variables).then(responseStub)
}
})
function responseStub(result) {
return {
json() {
return Promise.resolve(result)
},
ok: true,
}
}
2. Create a mock GraphQL server (Optional)
You only need this if you want a fallback to a mock server. This requires your schema in SDL format to be exported as a string from a .js file. We handle this by generating the file before running Cypress using get-graphql-schema
:
ORIGIN=https://some-url.com
SCHEMA_FILE=cypress/schema.js
echo "module.exports = \`" > $SCHEMA_FILE
node_modules/.bin/get-graphql-schema $URL >> $SCHEMA_FILE
echo "\`" >> $SCHEMA_FILE
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools'
import { graphql } from 'graphql'
// Your schema in SDL format exported as a string
import typeDefs from '../schema'
const schema = makeExecutableSchema({ typeDefs })
addMockFunctionsToSchema({ schema })
export function runQuery(query, variables) {
return graphql(schema, query, {}, {}, variables)
}