0

I have created Cypress e2e tests that use the following functions:

  • to mock the responses
export function getUserAndSupplier(): void {
    cy.intercept('GET', `${Cypress.env('BaseUrl')}/users/me`,
        {
            fixture: 'shared/Users/me.json',
        })
        .as('users');

    cy.intercept('GET', `${Cypress.env('BaseUrl')}/users/me/supplier`,
        {
            fixture: 'shared/Suppliers/supplier.json',
        })
        .as('supplier');
}
  • to check if responses are in accordance to the fixtures:
export function checkUserAndSupplier(): void {
    cy.wait('@users')
        .its('response.body')
        .should('not.be.undefined')
        .then((interception: any) => {
         
        //assertions on each field
        });

    cy.wait('@supplier')
        .its('response.body')
        .should('not.be.undefined')
        .then((interception: GetCurrentSupplierResponse) => {

         //assertions on each field
        });
}

Tests have Cucumber preprocessor implemented, the GIVEN and WHEN steps definition for given test are:

beforeEach(() => {
    // intercept user and supplier api
    getUserAndSupplier();
    // intercept GET /paymentProviders
    interceptPaymentProviders();
});

Given('User navigates to the {string} page', () => {
    cy.visit('/sell/payment-providers');
    // assert api calls on user and supplier
    checkUserAndSupplier();
});

When('User clicks on {string} button', () => {
    getActivationButton()
        .scrollIntoView()
        .contains('Activate')
        .should('be.visible')
        .and('not.be.disabled')
        .click();

    // Ensure Continue Button is disabled
    getContinueButton()
        .should('be.visible')
        .and('be.disabled');

});

while the .feature file test is:

Scenario: Happy path - activate payment method

Given User navigates to the "sell/payment-providers" page
When User clicks on "activate" button
Then User is able to successfully activate payment provider

The problem is that sometimes, despite having responses mocked using fixtures (they're not null or empty), 'response.body' property is undefined, which makes tests flaky. enter image description here

At the beginning I thought I have some asynchronous functions that lack await and make response.body being undefined, but this was not the case.

What may be the cause of this? And what makes it sometimes working, and sometimes not?

Fody
  • 23,754
  • 3
  • 20
  • 37
hubesal
  • 141
  • 3
  • 13

1 Answers1

0

It's hard to tell what exactly is going on, the code looks ok.

Here's some general tips to try.

Cache

It's possible the browser cache is interfering with the intercept. To avoid caching, add this

beforeEach(() => {
  Cypress.automation('remote:debugger:protocol', {
    command: 'Network.clearBrowserCache'
  })
  ...
})

Debug call sequence

To debug the network calls, combine the two intercepts and use callbacks to console.log what gets intercepted.

If something is changing the order of response, the problem may be caused by the sequence of cy.wait('@users') followed by cy.wait('@supplier') so combining the intercepts will catch that.

export function getUserAndSupplier(): void {
  cy.intercept('/users*', (req) => {
    if (req.url.endsWith('/me')) {
      console.log('users request', req)
      req.alias = 'users'
      req.reply({fixture: 'shared/Users/me.json'})
    }
    if (req.url.endsWith('/me/supplier')) {
      console.log('supplier request', req)
      req.alias = 'supplier'
      req.reply({fixture: 'shared/Suppliers/supplier.json'})
    }
  })
}

Or use a single alias for both paths and check inside the interception.

export function getUserAndSupplier(): void {
  cy.intercept('/users*', (req) => {
    if (req.url.endsWith('/me')) {
      req.reply({fixture: 'shared/Users/me.json'})
    }
    if (req.url.endsWith('/me/supplier')) {
      req.reply({fixture: 'shared/Suppliers/supplier.json'})
    }
  })
  .as('both')
}

export function checkUserAndSupplier(): void {

  const checkInterception = (interception) => {
    if (interception.request.url.endsWith('/me')) {
      console.log('users response', interception.response)
      // assertions for users
    }
    if (interception.request.url.endsWith('/me/supplier')) {
      console.log('supplier response', interception.response)
      // assertions for supplier
    }
  }

  cy.wait('@both').then(checkInterception);    // first interception
  cy.wait('@both').then(checkInterception);    // second interception
}

Lastly, something in interceptPaymentProviders() is interfering with the other intercepts.

Fody
  • 23,754
  • 3
  • 20
  • 37