19

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>
Sascha Hick
  • 331
  • 1
  • 4
  • 9

4 Answers4

16

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.

Richard Matsen
  • 20,671
  • 3
  • 43
  • 77
  • Ok I think this would be a useful feature for cy.intercept(). Thanks for your code! I have tried it and there is a minor thing missing. From intercept I get the request and with this request I can manipulate the response as you suggested. This actually works in my case now. `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' }) } }); });` – Sascha Hick Nov 28 '20 at 15:38
  • Yes you're right, the `req` controls the `res`. – Richard Matsen Nov 28 '20 at 19:02
  • This does not work in circleci for some reaon. Locally it passes fine. – Antti Tanskanen Jun 22 '21 at 09:49
12

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');
Paolo
  • 3,530
  • 7
  • 21
10

Cypress command cy.intercept has the times parameter that you can use to create intercepts that only are used N times. In your case it would be

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

See the cy.intercept example in the Cypress recipes repo https://github.com/cypress-io/cypress-example-recipes#network-stubbing-and-spying

gleb bahmutov
  • 1,801
  • 15
  • 10
0
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.

baklazan
  • 814
  • 6
  • 13