hubesal
hubesal

Reputation: 179

Cypress intercept blocks the request when it's called several times in a test run

I've created some tests in Cypress to add and duplicate article in our Angular application. The code for test ArticlesTest.js

describe('Shop articles single station', () => {
const productManagementPage = new ProductManagementPage()
const shopArticlesPage = new ShopArticlesPage()

before(() => {
    var credentials = 
    {
        "username": "[email protected]",
        "password": "strongPassword!"
    }

    cy.navigateToProductManagement(credentials)
})

beforeEach(() => {
    productManagementPage.shopArticlesProgrammingButton().click()
    shopArticlesPage.WaitUntilPageLoaded('/productmanagement/api/v1/articles/get', 'GetArticles')
})

it('Add article', () => {
    var randomNumber = RandomDataGenerator.GenerateRandomInt(1000,4999)
    var randomName = RandomDataGenerator.GenerateRandomString(20)
    var randomPrice = RandomDataGenerator.GenerateRandomDecimal(1,99)

    shopArticlesPage.newArticleButton().click()
    shopArticlesPage.saveButton().should('be.disabled')
    shopArticlesPage.undoButton().should('be.disabled')
    shopArticlesPage.deleteButton().should('be.disabled')
    shopArticlesPage.articlesList().should('not.exist')
    shopArticlesPage.articleNumberTextBox().should('be.enabled')

    shopArticlesPage.articleNumberTextBox().type(randomNumber)
    shopArticlesPage.articleNameTextBox().type(randomName)
    shopArticlesPage.articleUnitPriceTextBox().type(randomPrice)

    shopArticlesPage.undoButton().should('be.enabled')

    shopArticlesPage.saveButton().click()

    shopArticlesPage.newArticleButton().should('exist')
    shopArticlesPage.articlesList().should('exist')
    shopArticlesPage.saveButton().should('be.disabled')
    shopArticlesPage.undoButton().should('be.disabled')

})

it('Duplicate article', () => {
    var articleNumber = RandomDataGenerator.GenerateRandomInt(51,65)
    var newArticleNumber = RandomDataGenerator.GenerateRandomInt(1000, 4999)
    var newArticleName = RandomDataGenerator.GenerateRandomString(20)
    
    shopArticlesPage.articlesList().selectFromList(articleNumber)

    const articleUnitPrice = shopArticlesPage.articleUnitPriceTextBox().invoke('text')
    const vatCodeValue = shopArticlesPage.vatCodeDropDown().invoke('text')
    const cardCodeValue = shopArticlesPage.cardCodeDropDown().invoke('text')

    shopArticlesPage.duplicateArticleButton().click()
    shopArticlesPage.WaitUntilPageLoaded()
    shopArticlesPage.articleNumberTextBox().type(newArticleNumber)
    shopArticlesPage.articleNameTextBox().type(newArticleName)
    shopArticlesPage.saveButton().click()

    shopArticlesPage.newArticleButton().should('be.enabled')
})

WaitUntilPageLoaded() method code is:

WaitUntilPageLoaded(path, alias) {
    return cy.waitForRequestToComplete(path, alias)
}

which, in turn, is custom Cypress command:

Cypress.Commands.add('waitForRequestToComplete', (path, alias) => {
  cy.intercept('POST', path).as(alias)
  cy.wait('@' + alias).its('response.statusCode').should('be.ok')
})

In 1st beforeEach() run, there's no problem with intercepting GetArticles and waiting for it to complete. 1st test - beforeEach() method run The problem starts in 2nd test, as it looks like GetArticles is not intercepted, it's not called at all, though it's supposed to be. The problem doesn't exist when clicking through the application manually, and /articles/get is always invoked. enter image description here The test ends up with error message

Timed out retrying after 30000ms: cy.wait() timed out waiting 30000ms for the 1st request to the route: GetArticles. No request ever occurred.

I've also tried using other endpoint e.g. vatcodes/get, and it works perfectly. The problem occurs only for articles/get, but I don't see any trail that would tell my why this happens for articles endpoint.

What is the problem? Why Cypress "blocks" 2nd call to this endpoint? What's more interesting, the problem doesn't exist for GetFeatures alias, which is created in an identical way.

Upvotes: 3

Views: 3529

Answers (3)

Saeed Mansoori
Saeed Mansoori

Reputation: 449

Make sure the network intercept is registered before the application makes the call.

it('is registered too late', () => {
  cy.intercept('/todos').as('todos')
  cy.visit('/')
  cy.wait('@todos')
})

In our case, we need to register the intercept before visiting the page. Once the page is loaded, the application fetches the todo items, and everything is working as expected.

you can see this link: https://glebbahmutov.com/blog/cypress-intercept-problems/

Upvotes: 3

Gus
Gus

Reputation: 7525

Have you resolved this?

I'm using this config:

Given('a GraphQL service error is thrown', () => {
  cy.intercept({ method: 'POST', url: '/uat/graphql', times: 1 }, { forceNetworkError: true });
});

With times: 1. But the interception does not block the request now.

I found times in the docs.

Upvotes: 0

Michael Hines
Michael Hines

Reputation: 1108

If I'm reading the situation correctly, the last log image is the failing test.

There is no (xhr) 200 /productmanagement/api/v1/articles/get showing there.

It goes straight from api/v1/subscriptionfeatures/get to api/v1/vatcodes/get, but in the first test the api/v1/articles/get was between those two calls.

If it occurs later in the screenshot, add an increased timeout to catch it (the same intercept can use the longer timeout in both tests, but it won't delay the first test).

This may mean you have found a bug in the app - it seems that a "Duplicate" action should have the same POSTs as an "Add" action.

Upvotes: 6

Related Questions