2

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": "test@testqa.com",
      "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.

Paolo
  • 3,530
  • 7
  • 21
Pix81
  • 585
  • 3
  • 15
  • 33

3 Answers3

3

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

Paolo
  • 3,530
  • 7
  • 21
  • This is really close, but I get Cannot read properties of undefined (reading: resident) ``` // cy.fixture('resident').then((json) => { // json.data.user.user.status = 'NEEDS_MOVE_IN_COST_SET'; // console.log('json reply: ', json); // cy.intercept('POST', '/graphql', (req: any) => { // if (req.body.operationName === 'SingleResident') { // req.reply({ // body: {json} // }) // } // }); // }); ``` DOES return the query in the network tab but with the word json in the body, so the test fails. Very close. – Pix81 Dec 21 '22 at 22:40
  • I can't see where the `resident` property is used unfortunately. It's not in the question, nor in the comment. But Cypress can obviously see it because it complains about it's parent being `undefined`. – Paolo Dec 22 '22 at 05:25
  • I'm assuming you put `//` in for new line characters. Try adding that code to the question in a pretty fashion, someone may be able to spot the thing to change. – Paolo Dec 22 '22 at 05:28
  • Here is my code that seems to be changing the request in every way I want it changed. Note this is the actual code and not the example so doesn't match perfectly: – Pix81 Dec 22 '22 at 20:49
  • ``` ``` cy.fixture('resident').then( (json) => { json.data.resident.resident.invite.status = 'NOT_SENT'; json.data.resident.resident.status = 'NEEDS_MOVE_IN_COST_SET'; cy.intercept('POST', '/graphql', (req) => { if (req.body.operationName === 'SingleResident') { aliasQuery(req, 'MoveInCostResident'); req.reply((response: any) => (response.body = json)); return; } }) }, ); ``` However, i get this in the response: – Pix81 Dec 22 '22 at 20:50
  • ``` {errors: [{message: "401: Unauthorized",…}], data: {,…}} data : {,…} errors : [{message: "401: Unauthorized",…}] ``` Everything under data is what I expect. I assume the 401 call has to do with a problem in the source code. This is a generic error that seems to happen when the intercept isn't what cypress wants and the log out is the result. I assume it has something to do with the context of the test and not the shape of the intercept. So I think this is as close to a solution as I can get – Pix81 Dec 22 '22 at 20:51
  • Marking this answer as the solution as it does successfully mutate the json response and I'm no longer getting errors about undefined params – Pix81 Dec 22 '22 at 20:53
3

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"]
}
Genevieve OR
  • 182
  • 8
1

@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))
  }
})

Genevieve OR
  • 182
  • 8
jjhelguero
  • 2,281
  • 5
  • 13