cypresscypress-intercept

Cypress test with multiple interceptors


I am trying to write cypress tests that check if data is received into my data table from the API.

One test to check the data, another test to check for an error message if there is no data from the API.

To simulate the API's response (one with data and one without) I am using cy.intercept().

I can't seem to get two separate intercepts to work within my single test file.

What is the recommended procedure to test multiple different intercepts in the same cypress test file, or should they be in separate files?

Any help appreciated!

    describe('Display Data Page', () => {

    beforeEach(() => {

        // Fake the backend Http response using the json file in our cypress fixtures folder.
        cy.intercept('GET', 'https://localhost:3000/GetData', {fixture:'my_data.json'}).as('my_data');

        cy.visit('/display-data');
        
    });

    it('Should display a list of my data', () => {

        cy.wait('@my_data');

        cy.get('.dataGrid').should('not.be.empty');
        cy.get('.dataGrid').should("contain", "Blah");
  
    });

    it('Should display a error message when api is offline', () => {

        // Reply with a HTTP 400 bad request to test error message
        cy.intercept('GET', 'https://localhost:3000/GetData', {status: 400}).as('my_error_data');

        cy.wait('@my_error_data');

        cy.get('.errorMessage').should('not.be.empty');
        cy.get('.errorMessage').should("contain", "Error: API is non-responsive!");
  
    });

});

Solution

  • The basic problem is that the intercept my_error_data is being set too late.

    Since intercepts are listeners, they need to be set up before they code that triggers the backend call. That trigger is cy.visit(), but in the second test it runs before the intercept is set up.

    Move the visit out of the beforeEach() and into the tests to fix it.

    it('Should display a list of my data', () => {
    
      cy.intercept('GET', 'https://localhost:3000/GetData', {fixture:'my_data.json'})
        .as('my_data')
    
      cy.visit('/display-data')
      cy.wait('@my_data')
    
      ... 
    })
    
    it('Should display a error message when api is offline', () => {
    
      cy.intercept('GET', 'https://localhost:3000/GetData', {status: 400})
        .as('my_error_data')
    
      cy.visit('/display-data')
      cy.wait('@my_error_data')
    
      ...
    })
    

    Keeping the beforeEach()

    If you really want to keep the beforeEach() structure, make the StaticResponse part of the cy.intercept() dynamic.

    You would only need one intercept with that pattern.

    
    let staticResponses = [
      {fixture:'my_data.json'},
      {status: 400}
    ]
    
    beforeEach(() => {
    
      const response = staticResponses.shift() // extract 1st response and reduce array
    
      cy.intercept('GET', 'https://localhost:3000/GetData', response)
        .as('my_data')
    
      cy.visit('/display-data')
    })
    
    it('Should display a list of my data', () => {
      cy.wait('@my_data')
      ...
    })
    
    it('Should display a error message when api is offline', () => {
      cy.wait('@my_data')  // same alias
      ...
    })
    

    Example test

    Here's an example test to verify the principle.

    It turns out that Cypress is smart enough to know when the staticResponse is a fixture that should be sent as body, and when the object represents the whole response.

    let staticResponses = [
      {fixture:'example.json'},
      {statusCode: 400}             // use statusCode instead of status
    ]
    
    beforeEach(() => {
      const response = staticResponses.shift() // extract 1st response and reduce array
    
      cy.intercept('GET', 'https://localhost:3000/GetData', response)
        .as('my_data')
    
      cy.visit('/display-data')
    })
    
    it('Should display a list of my data', () => {
      cy.wait('@my_data')
        .its('response.body')
        .should('have.property', 'email', 'hello@cypress.io')
    })
    
    it('Should display a error message when api is offline', () => {
      cy.wait('@my_data')
        .its('response')
        .should('have.property', 'statusCode', 400)
    })
    

    enter image description here