Eduardo Pedroso
Eduardo Pedroso

Reputation: 879

Cypress route function not detecting the network request

I'm trying to wait for a request made by my application but Cypress is not detecting it on cy.wait

    cy.server();
    cy.getAuthenticatedUrl();
    cy.route('POST', '/showroom/validate').as('uploadShowroom');

    cy.get('[data-testid=Next]').click();

    cy.uploadFile('[id=uploadArea]', 'testfile-valid.xlsx', 'application/vnd.ms-excel');

    cy.wait('@uploadShowroom');

    cy.contains('FILE UPLOAD DONE');

If I check my console during the tests, I can see that the request was made to my server

screenshot-console

Both my client and my server are running local but in different ports.

The error is the following: CypressError: Timed out retrying: cy.wait() timed out waiting 5000ms for the 1st request to the route: 'uploadShowroom'. No request ever occurred.

Upvotes: 5

Views: 6291

Answers (3)

rickroyce
rickroyce

Reputation: 1032

I ran in something similar. The trick was not to check the route against a string but against a regular expression. Try this to match your POST route:

cy.route('POST', /showroom\/validate/).as('uploadShowroom');
// [...]
cy.wait('@uploadShowroom');

If you can see the the route is matching in cypress command log (yellow badge beside the route), it should do, what you want.

Upvotes: 1

Richard Matsen
Richard Matsen

Reputation: 23533

I think this is because your form is using native form submit, but Cypress' cy.route() only responds to XHR calls (at the moment).

There is a big discussion in issue #170.

Gleb Bahmutov has an interesting idea in this comment, code in this repository. Essentially he 'mocks' the native submit with an XHR submit, on the fly.

I tried out a variation which gets closer to your scenario. Follow the repository READ.ME to set up the test, but first update the Cypress version in package.json. Add the file to be uploaded into /cypress/fixtures.

Then try the following spec.

The third test is an alternative which uses cy.url() instead of cy.route().

uploadFile command (or similar variation)

Cypress.Commands.add('uploadFile', (fileName, selector) =>
  cy.get(selector).then(subject => {
    return cy
      .fixture(fileName, 'base64')
      .then(Cypress.Blob.base64StringToBlob)
      .then(blob => {
        const el = subject[0];
        const testFile = new File([blob], fileName, {
          type: 'application/vnd.openxmlformatsofficedocument.spreadsheetml.sheet',
        });
        const dataTransfer = new DataTransfer();
        dataTransfer.items.add(testFile);
        el.files = dataTransfer.files;
        return subject;
      });
  })
);

Function to 'mock' the native submit with XHR (place at top of Spec)

const mockNativeSubmitWithXhr = (form$) => {
  let win
  cy.window().then(w => {
    win = w
  })
  form$.on('submit', e => {
    e.preventDefault()
    const form = new FormData(e.target)
    const XHR = new win.XMLHttpRequest()
    XHR.onload = response => {
      win.document.write(XHR.responseText)
      win.history.pushState({}, '', XHR.url)
    }
    XHR.open(e.target.method, e.target.action)
    XHR.send(form)
    return true
  })
}

Spec

describe('waiting for form-data post', () => {

  beforeEach(() => {
    cy.task('deleteFile', '../../uploads/Sample_data.xlsx')
    cy.visit('localhost:3000')
    cy.get('input[name="userid"]').type('[email protected]')
  })

  it('upload with native form submit (fails because of native event)', () => {
    cy.server()
    cy.route('POST', '/upload').as('upload');

    cy.uploadFile('Sample_data.xlsx', '[id=fileToUpload]')
    cy.get('input[type="submit"]').click()

    cy.wait('@upload');
    cy.readFile('uploads/Sample_data.xlsx') // check saved file
  })

  it('upload with form submit mocked to XHR send (succeeds)', () => {
    cy.server()
    cy.route('POST', '/upload').as('upload');

    cy.uploadFile('Sample_data.xlsx', '[id=fileToUpload]')
    cy.get('form').then(form => mockNativeSubmitWithXhr(form))
    cy.get('input[type="submit"]').click()

    cy.wait('@upload');
    cy.readFile('uploads/Sample_data.xlsx')
  })

  it('upload with native form submit (testing url has changed)', () => {
    cy.uploadFile('Sample_data.xlsx', '[id=fileToUpload]')
    cy.get('input[type="submit"]').click()

    cy.url().should('eq', 'http://localhost:3000/upload')
    cy.readFile('uploads/Sample_data.xlsx')
  })
})

Task to remove uploaded file between tests (modify '/cypress/plugins/index.js')

const fs = require('fs')

module.exports = (on, config) => {
  on('task', {
    deleteFile: (path) => {
      if (fs.existsSync(path)) {
        fs.unlinkSync(path)
      }
      return null
    }
  })
}

Upvotes: 4

Julia Passynkova
Julia Passynkova

Reputation: 17899

Try to override default timeout of wait:

cy.wait('@uploadShowroom', {timeout: 10000);

Upvotes: -3

Related Questions