Ways to test if my app is making the correct amount of api calls

Viewed 50

I'm testing a react app with cypress, and cypress is really good at checking if atleast n many are calls are made on load, and not so good at checking if only those calls were made. The app itself is a pretty standard react app that uses window.fetch for api calls. Is there another service, like cypress something similar, that's got the ability to test that in an automated fashion?

For instance, if you visit the site logged in we have three config calls. If a developer commits code that accidentally calls one of those twice, ideally I'd like an automated test to catch that.

I don't want to do it in Cypress because it seems like that's not what the product is really intended to do unless you hack it with an undocumented solution.

1 Answers

Seems like you need a hard wait to ensure you check after all calls have been issued.

Also recommend stubbing so that there's no latency waiting for server response.

it('check for excess calls', () => {

  cy.intercept('https://jsonplaceholder.typicode.com/todos/1', {}).as('fetch')

  cy.visit('/').then(() => {

    // wait for expected calls
    cy.wait('@fetch')
    cy.wait('@fetch')
    cy.wait('@fetch')

    cy.wait(500)             
    cy.get('@fetch.all')     // check the call count
      .should(calls => {
        expect(calls).to.have.length(3)  // no extra calls
      })
  })
})

Tested with this app HTML

<script>
  fetch('https://jsonplaceholder.typicode.com/todos/1')
  fetch('https://jsonplaceholder.typicode.com/todos/1')
  fetch('https://jsonplaceholder.typicode.com/todos/1')
</script>

You may want to burn-test to get the right wait time, see Burning Tests with cypress-grep


Alternatively you can wait four times and catch the error


it('check for excess calls', () => {
  cy.intercept('https://jsonplaceholder.typicode.com/todos/1', {}).as('fetch')
  cy.visit('html/call-limit.html').then(() => {

    cy.wait('@fetch')
    cy.wait('@fetch')
    cy.wait('@fetch')

    Cypress.once('fail', (error) => {
      // catch ignore failure on 4th cy.wait('@fetch')
      if (error.message.includes('No request ever occurred')) { 
        return
      }
      throw error  // rethrow to fail for another reason
    })
    cy.wait('@fetch')  // should fail and trigger listener above

    cy.get('@fetch.all')
      .should(calls => {
        expect(calls).to.have.length(3)
      })
  })
})
Related