cypresscypress-intercept

Intercept for one OR another API - find only first asset


On a webpage I have a list of images and documents. Images comes from different server and have source /img/image/** and documents comes from my server and have source like /content/docs/*

The problem is, in Cypress (typescript), I want to intercept for images OR documents, as on the page can be only images, or only documents, or even both in random order.

I want to be sure, at least one asset is loaded.

First I tried:

      cy.intercept({
        method: 'GET',
        url: /\/content\/docs\/.*|\/img\/image\/.*/,
      }).as('Thumbnail');
cy.visit(URL);
 cy.wait('@Thumbnail');

But no request even occurs this way.

If I just use

 cy.intercept('GET', '/img/image/**').as('Thumbnail');
cy.visit(URL);
     cy.wait('@Thumbnail');

This works, but of course if only images are present.

I also tried something like this:

export const waitForFirstAsset = (): void => {
  let assetIntercepted = false;

  // Create a helper function to wait for the first request
  const waitForRequest = (): void => {
    // Wait for either request
    cy.wait(['@imageRequest', '@documentRequest'], { timeout: 10000 }).then(
      (interceptions): void => {
        if (!assetIntercepted) {
          assetIntercepted = true;

          const interceptedRequest = interceptions[0];
        
        }
      },
    );
  };

  // Call the waitForRequest function
  waitForRequest();
};


 cy.intercept('GET', '/img/image/**').as('imageRequest');
    cy.intercept('GET', '/content/docs/**').as('documentRequest');

    // Visit the page
    cy.visit(URL);

    // Wait for the first asset request (either image or document)
    waitForFirstAsset();

This again works for images, however it intercepts all images, not just the first, but if no documents are on page, it fails with waiting for documentRequest.

Any idea, how can I just intercept for the FIRST loaded image or document, no need to check for all. Just want to be sure, at least one is loaded.


Solution

  • The first intercept you are using should work, I tried a basic replication of the problem - it catches both types of request.

    Here's my example - the only difference is I added a stub reply since there's no server to respond.

    cy.intercept({
      method: 'GET',
      url: /\/content\/docs\/.*|\/img\/image\/.*/,
    }, {}).as('resource')
    
    // fire an image request and wait for the intercept
    cy.window().then(win => {
      win.fetch('https://my-site/img/image/sub-path/1.jpg')
    })
    cy.wait('@resource').its('request.url')
      .should('contain', '/img/image/')
    
    // fire an doc request and wait for the intercept
    cy.window().then(win => {
      win.fetch('https://my-site/content/docs/sub-path/a.js')
    })
    cy.wait('@resource').its('request.url')
      .should('contain', '/content/docs/')
    

    enter image description here

    Another variation is to move the regex inside the RouteHandler function and apply it to the URL string (may help you debug the issue)

    cy.intercept(/my-site/, (req) => {
      const regex = /\/content\/docs\/.*|\/img\/image\/.*/
      if (req.url.match(regex)) {
        req.alias = 'resource'
      }
      req.reply({})  // just for my demo code
    })
    

    Using two intercepts

    The second example works if you assign the same alias to both intercepts.

    To stop catching multiple resources, there is a times:1 option that turns off the intercept after the first catch. I'm not sure you actually need it, since you only need one cy.wait() to catch the first request - the rest will catch but the test will ignore them.

    Again, I added a stub for the demo but you wouldn't necessarily need to do so.

    cy.intercept({method: 'GET', url: '/img/image/**', times: 1},  
      (req) => req.reply({}))
      .as('resource')
    
    cy.intercept({method: 'GET', url: '/content/docs/**', times: 1},
      (req) => req.reply({}))
      .as('resource')
    
    cy.window().then(win => {
      win.fetch('https://my-site/img/image/sub-path/1.jpg')
    })
    cy.wait('@resource').its('request.url')
      .should('contain', '/img/image/')
    
    cy.window().then(win => {
      win.fetch('https://my-site/content/docs/sub-path/a.js')
    })
    cy.wait('@resource').its('request.url')
      .should('contain', '/content/docs/')
    

    I also reversed the order of the fetches to make sure there's not some issue with the order of the intercepts, and I still get passing test.

    enter image description here