Change fixture response in cypress for the same url with intercept

Viewed 10952

I am trying to write a test with the new cypress 6 interceptor method (Cypress API Intercept). For the test I am writing I need to change the reponse of one endpoint after some action was performed.

Expectation:

I am calling cy.intercept again with another fixture and expect it to change all upcomming calls to reponse with this new fixture.

Actual Behaviour:

Cypress still response with the first fixture set for the call.

Test Data:

In a test project I have recreated the problem:

test.spec.js

describe('testing cypress', () => {


    it("multiple responses", () => {

        cy.intercept('http://localhost:4200/testcall', { fixture: 'example.json' });

        // when visiting the page it makes one request to http://localhost:4200/testcall
        cy.visit('http://localhost:4200');
        cy.get('.output').should('contain.text', '111');

        // now before the button is clicked and the call is made again
        // cypress should change the response to the other fixture
        cy.intercept('http://localhost:4200/testcall', { fixture: 'example2.json' });

        cy.get('.button').click();
        cy.get('.output').should('contain.text', '222');
        
    });

});

example.json

{
  "text": "111"
}

example2.json

{
  "text": "222"
}

app.component.ts

import { HttpClient } from '@angular/common/http';
import { AfterViewInit, Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {

  public text: string;

  public constructor(private httpClient: HttpClient) { }

  public ngAfterViewInit(): void {
    this.loadData();
  }

  public loadData(): void {
    const loadDataSubscription = this.httpClient.get<any>('http://localhost:4200/testcall').subscribe(response => {
      this.text = response.body;
      loadDataSubscription.unsubscribe();
    });
  }

}

app.component.html

<button class="button" (click)="loadData()">click</button>

<p class="output" [innerHTML]="text"></p>
4 Answers

Slightly clumsy, but you can use one cy.intercept() with a Function routeHandler, and count the calls.

Something like,

let interceptCount = 0;  

cy.intercept('http://localhost:4200/testcall', (req) => {   
  req.reply(res => {     
    if (interceptCount === 0 ) {
      interceptCount += 1;
      res.send({ fixture: 'example.json' })
    } else {
      res.send({ fixture: 'example2.json' })
    }
  }); 
});

Otherwise, everything looks good in your code so I guess over-riding an intercept is not a feature at this time.

As of Cypress v7.0.0 released 04/05/2021, cy.intercept() allows over-riding.

We introduced several breaking changes to cy.intercept().

  • Request handlers supplied to cy.intercept() are now matched starting with the most recently defined request interceptor. This allows users to override request handlers by calling cy.intercept() again.

So your example code above now works

cy.intercept('http://localhost:4200/testcall', { fixture: 'example.json' });

// when visiting the page it makes one request to http://localhost:4200/testcall
cy.visit('http://localhost:4200');
cy.get('.output').should('contain.text', '111');

// now cypress should change the response to the other fixture
cy.intercept('http://localhost:4200/testcall', { fixture: 'example2.json' });

cy.get('.button').click();
cy.get('.output').should('contain.text', '222');
const requestsCache = {};
export function reIntercept(type: 'GET' | 'POST' | 'PUT' | 'DELETE', url, options: StaticResponse) {
    requestsCache[type + url] = options;
    cy.intercept(type, url, req => req.reply(res => {
        console.log(url, ' => ', requestsCache[type + url].fixture);
        return res.send(requestsCache[type + url]);
    }));
}

Make sure to clean requestsCache when needed.

Related