How to get cypress to dynamically update a fixture to a graphql call

1k Views Asked by At

I need to mutate a graphql call in Cypress to where I can change certain key:value pairs within a fixture depending on the test.

I know I can call a graphql fixture with a format similar to this:

  cy.intercept('POST', '/graphql', (req) => {
    if (req.body.operationName === 'operationName') {
      req.reply({ fixture: 'mockData.json'});
    }
  }

but pretend mockData has the following shape:

 data: {
  "user": {
    "user": {
      "userId": 123,
      "inviteId": "123",
      "status": "NEEDS_MORE",
      "firstName": "Testy",
      "lastName": "McTesterson",
      "email": "[email protected]",
      "phone": "3129876767",
      "user": null,
      "invite": {
        "id": "12345",
        "sentAt": null,
        "sendDate": null,
        "status": "NOT_SENT",
        "__typename": "Invite"
      },
    },
  }
}

How would I intercept the graphql call with all the info in mockData.json but change "status": "NEEDS_MORE" to "status": "CLAIMED" in my test without changing the rest of the fixture? The idea would be that in each it block of a spec, I re-use the same fixture but change the status, and have different assertions.

My attempts so far either only send the status without the rest of the data or only send the fixture without mutating anything. There is cypress documentation on how to do this in rest, but not in graphql. We're using typescript.

3

There are 3 best solutions below

7
On BEST ANSWER

You can read the fixture first, make the modification before the reply

cy.fixture('mockData.json').then(data => {

  data.user.user.status = 'CLAIMED'

  cy.intercept('POST', '/graphql', (req) => {

    // according to one reference, this is needed
    const g = JSON.parse(req.body)

    if (g.operationName === 'operationName') {

      req.reply({
        body: {data}    // same reference shows reply stubbing in this format
      })
    }
  }
})

Ref: Smart GraphQL Stubbing in Cypress

0
On

@Paolo's answer is good. An alternative to avoid using cy.fixture().then()

const mockedData = require('path/to/fixture/mockData.json')

// later in your test block

mockedData.user.user.status = 'CLAIMED'

cy.intercept('POST', '/graphql', (req) => {
  if (req.body.operationName === 'operationName') {
    req.reply((res) => (res.body.data = mockedData))
  }
})

0
On

Consider using a dynamic import to read the fixture.

cy.intercept('POST', '**/graphql', async (req) => {

  const data = await import('../fixtures/mockData.json')
  data.user.user.status = 'CLAIMED'

  if (req.body.operationName === 'operationName') {
    req.reply({
      body: {data}
    })
  }
})

Since you have typescript set up, add resolveJsonModule to tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["es5", "dom"],
    "types": ["cypress", "node"],
    "resolveJsonModule": true
  },
  "include": ["**/*.ts"]
}