cypress icon indicating copy to clipboard operation
cypress copied to clipboard

Clicking anchor link to download file causes page load timeout

Open hiatien19 opened this issue 4 years ago • 46 comments
trafficstars

i was update Cypress 6.4.0 but i cannot click button download error_download_file

file source: error_download_file_2

source: cypress_download.zip

hiatien19 avatar Feb 02 '21 01:02 hiatien19

I can recreate this error with the test code below:

it('download file', ({ pageLoadTimeout: 5000 }), () => {
  cy.visit('https://people.sc.fsu.edu/~jburkardt/data/csv/csv.html')
  cy.get('a[href="addresses.csv"]').click()
})
Screen Shot 2021-02-03 at 2 45 08 PM Screen Shot 2021-02-03 at 2 45 58 PM

jennifer-shehane avatar Feb 03 '21 08:02 jennifer-shehane

I am facing the same problem. Clicking on the Download button change window.location.href to download the file, also triggers the beforeunload event. We are downloading the file only, not redirecting towards a page actually, but for the redirection, cypress wait for a load event to be triggered by the application but as no redirection actually is happening it gets page load timeout error. I tried stopPropagation on "window:before:unload" event but didn't work. If we can invoke the load event during the wait or can execute the stopPropagation on the correct state it can be resolved I guess.

Cypress version: 6.5.0 OS : Windows 10

sarja510 avatar Feb 18 '21 12:02 sarja510

Hi, @jennifer-shehane I'm also facing the same issue even after updating Cypress 6.5.0. Clicking on a button downloads the file, but after downloading the file, the cypress waiting for page load which is not the expected behavior. please suggest a workaround for this problem.

kiransurakanti avatar Feb 22 '21 06:02 kiransurakanti

I got a workaround with the following issue,

What actually was happening in my case is that after clicking the download button a redirection was happening to download the file. From the application code: window.location.href was changing to download the file on click event. When cypress gets the redirection it waits for a page load event to get fired from AUT for continuing further. As no actual page redirection was happening so it got stuck and got page load timeout. So I tried the following workaround and it is working fine for my case:

Solution/Workaround:

All I needed was to fire a page load event to execute other cypress commands after clicking the download button rather than getting page load timeout. So before clicking the Download button or targeted file I added an event listener ‘click’ to listen out for the event and did something to trigger the page load event. Here is a tricky part, on event handling I triggered window.location.reload. But if I instantly trigger that on click event it will work but the file will not get downloaded. So I set a timeout of 5 sec, it may vary as per our requirement to download the file, after that, I am triggering window.document.location.reload(). This reloads the page and triggers a page load event. As soon as cypress get the page load event it continues executing further commands

the following solution worked for me fine:

cy.window().document().then(function (doc) {
  doc.addEventListener('click', () => {
    setTimeout(function () { doc.location.reload() }, 5000)
  })
  cy.get('[ng-click="vm.export()"]').click()
})

I hope cypress will give a proper solution for this case, till then anyone can use this workaround. @jennifer-shehane @hiatien19 @kiransurakanti

sarja510 avatar Feb 25 '21 08:02 sarja510

I'm experiencing the same issue here. The solution proposed by @sarja510 works until a new version fix it.

AdrianHL avatar Mar 02 '21 14:03 AdrianHL

the following solution worked for me fine:

cy.window().document().then(function (doc) {
  doc.addEventListener('click', () => {
    setTimeout(function () { doc.location.reload() }, 5000)
  })
  cy.get('[ng-click="vm.export()"]').click()
})

I hope cypress will give a proper solution for this case, till then anyone can use this workaround. @jennifer-shehane @hiatien19 @kiransurakanti

Unfortunately, this doesn't seem to be enough. The test seems to succeed even if the file to be downloaded doesn't exist (404s etc.). You can confirm it by changing URL of the file to be downloaded:

cy.intercept('/', (req) => {
    req.url += '-this-url-doesnt-exist';
});

I fixed it by intercepting the request and checking the status code of the response:

cy.window().document().then(function (doc) {
  doc.addEventListener('click', () => {
    setTimeout(function () { doc.location.reload() }, 5000)
  })
  
  /* Make sure the file exists */
  cy.intercept('/', (req) => {
    req.reply((res) => {
      expect(res.statusCode).to.equal(200);
    });
  });

  cy.get('[ng-click="vm.export()"]').click()
})

mklepaczewski avatar Mar 04 '21 16:03 mklepaczewski

@mklepaczewski This solution worked for me, thanks, and also to @sarja510 for the original approach. huge relief to be unblocked!

JoeKellyFR avatar Mar 15 '21 18:03 JoeKellyFR

@jennifer-shehane

I got a workaround with the following issue,

What actually was happening in my case is that after clicking the download button a redirection was happening to download the file. From the application code: window.location.href was changing to download the file on click event. When cypress gets the redirection it waits for a page load event to get fired from AUT for continuing further. As no actual page redirection was happening so it got stuck and got page load timeout. So I tried the following workaround and it is working fine for my case:

Solution/Workaround:

All I needed was to fire a page load event to execute other cypress commands after clicking the download button rather than getting page load timeout. So before clicking the Download button or targeted file I added an event listener ‘click’ to listen out for the event and did something to trigger the page load event. Here is a tricky part, on event handling I triggered window.location.reload. But if I instantly trigger that on click event it will work but the file will not get downloaded. So I set a timeout of 5 sec, it may vary as per our requirement to download the file, after that, I am triggering window.document.location.reload(). This reloads the page and triggers a page load event. As soon as cypress get the page load event it continues executing further commands

the following solution worked for me fine:

cy.window().document().then(function (doc) {
  doc.addEventListener('click', () => {
    setTimeout(function () { doc.location.reload() }, 5000)
  })
  cy.get('[ng-click="vm.export()"]').click()
})

I hope cypress will give a proper solution for this case, till then anyone can use this workaround. @jennifer-shehane @hiatien19 @kiransurakanti

@sarja510 This solution is worked for me.Thank You.

swatiamberkar avatar Mar 18 '21 07:03 swatiamberkar

This might be a very stupid question, but can you please let me know what is this doing

cy.get('[ng-click="vm.export()"]').click()

@mklepaczewski

shilpajain09 avatar Mar 31 '21 20:03 shilpajain09

This might be a very stupid question, but can you please let me know what is this doing

cy.get('[ng-click="vm.export()"]').click()

@mklepaczewski

ng-click="vm.export()" is just a selector. It clicks the first(?) element with attribute ng-click="vm.export()". So, for example if I had this in HTML:

<a href="https://example.com/" ng-click="vm.export()">Click here</a>

then the mentioned line would find this element and click it. If your link/button has id my-button then you would replace it with something like cy.get('#my-button').click()

mklepaczewski avatar Mar 31 '21 20:03 mklepaczewski

@mklepaczewski thanks a lot for your prompt response.

Are we verifying somewhere that the file is downloaded successfully?

shilpajain09 avatar Mar 31 '21 20:03 shilpajain09

@mklepaczewski thanks a lot for your prompt response.

Are we verifying somewhere that the file is downloaded successfully?

You can find it in Cypress.config('downloadsFolder');

noothaithinh avatar Apr 08 '21 10:04 noothaithinh

Any updates on this? Will it be released soon?

MCFreddie777 avatar May 20 '21 12:05 MCFreddie777

@jennifer-shehane when are you going to release patch for this issue, it is huge bug, it is 7.5.0 already and no cure of this

yasinitskyi avatar Jun 24 '21 12:06 yasinitskyi

Hitting this all over the place as well. I'm glad it's not just me struggling with it. Added a watch to this. Hopefully it gets sorted soon :)

samanthakirby avatar Jul 21 '21 23:07 samanthakirby

Any chance for a fix for this? 8.1 and bug still is standing strong

Jacek-fstack avatar Aug 02 '21 12:08 Jacek-fstack

We are also struggling with this. A fix would be really great! Thanks

mac503 avatar Aug 11 '21 16:08 mac503

@sarja510 pretty slick, love it, and it is working for me :)

bahmutov avatar Sep 16 '21 21:09 bahmutov

Facing the same issue. Any solution?

devsrihari4 avatar Sep 27 '21 16:09 devsrihari4

@sarja510 the same issue here.

swiec-qualio avatar Oct 11 '21 18:10 swiec-qualio

The work around is flaky IME so a real fix would be greatly appreciated!

jethrolarson avatar Oct 26 '21 00:10 jethrolarson

@sarja510

I have tried the workaround you posted and it is returning null from the reload() method. Could you see what might be going wrong with the test. and the "Download" button I am click has no href link.

reload null

raghuvardhan4b7 avatar Nov 03 '21 17:11 raghuvardhan4b7

@sarja510

I have tried the workaround you posted and it is returning null from the reload() method. Could you see what might be going wrong with the test. and the "Download" button I am click has no href link.

reload null

I have this problem too!

OrigoTom avatar Nov 10 '21 15:11 OrigoTom

I got a workaround with the following issue,

What actually was happening in my case is that after clicking the download button a redirection was happening to download the file. From the application code: window.location.href was changing to download the file on click event. When cypress gets the redirection it waits for a page load event to get fired from AUT for continuing further. As no actual page redirection was happening so it got stuck and got page load timeout. So I tried the following workaround and it is working fine for my case:

Solution/Workaround:

All I needed was to fire a page load event to execute other cypress commands after clicking the download button rather than getting page load timeout. So before clicking the Download button or targeted file I added an event listener ‘click’ to listen out for the event and did something to trigger the page load event. Here is a tricky part, on event handling I triggered window.location.reload. But if I instantly trigger that on click event it will work but the file will not get downloaded. So I set a timeout of 5 sec, it may vary as per our requirement to download the file, after that, I am triggering window.document.location.reload(). This reloads the page and triggers a page load event. As soon as cypress get the page load event it continues executing further commands

the following solution worked for me fine:

cy.window().document().then(function (doc) {
  doc.addEventListener('click', () => {
    setTimeout(function () { doc.location.reload() }, 5000)
  })
  cy.get('[ng-click="vm.export()"]').click()
})

I hope cypress will give a proper solution for this case, till then anyone can use this workaround. @jennifer-shehane @hiatien19 @kiransurakanti

thank you you saved my life. you should work at cypress and fix this kind of thing

recitogigih avatar Dec 01 '21 07:12 recitogigih

Also have been seeing the same issue for a while and using the suggested workaround. However we download a lot of files and check their content so doing these reloads really hurt our execution time.

@jennifer-shehane is there any vague ETA on this? Just want to consider any other solutions like just hitting the download endoints, however that would not be an E2E test.

rodrigo-vazquez avatar Dec 08 '21 17:12 rodrigo-vazquez

Facing similar issues while downloading blob in UI, workaround by @sarja510 works in latest version 9.1.1 for my CI pipeline but reloads really somehow hurts the execution time as after reload, we again have to reach same state in the UI where we left off before reloads. This doesn't seem to capture real user behaviour. @jennifer-shehane Would love to know if Cypress is working on it and releasing the fix soon.

Edit: Cypress released 9.2.0 yesterday but again no update on this issue in changelog.

souravs17031999 avatar Dec 21 '21 14:12 souravs17031999

Here with the same issue. I'm using Cypress with an SPA (Angular) so I never have page load events. Here is my .html file:

      <button mat-raised-button color="primary" id="btn-download-output" (click)="downloadFile(theAPIJob.presignedURL, theAPIJob.destFilename)">
        <mat-icon class="cloud_download_button">cloud_download</mat-icon>
        {{theAPIJob.destFilename}}
      </button>

Clicking the button triggers the following downloadFile JS function:

  downloadFile(signedURL: string, fileName: string) {
    const link = document.createElement('a');
    link.setAttribute('target', '_self');
    link.setAttribute('href', signedURL);
    link.setAttribute('download', fileName);
    document.body.appendChild(link);
    link.click();
    link.remove();
  }

Cypress successfully saves the file to the downloads folder, but then times out waiting for the page to load. There is no further activity on the webpage after the user downloads. What I need Cypress to do is execute a cy.readFile(outputFile) after the download completes to confirm it was successfully downloaded.

breencp avatar Dec 24 '21 10:12 breencp

@sarja510

I have tried the workaround you posted and it is returning null from the reload() method. Could you see what might be going wrong with the test. and the "Download" button I am click has no href link.

reload null

- doc.location.reload();
+ doc.location?.reload();

or

- doc.location.reload();
+ doc.location && doc.location.reload();

amowu avatar Jan 20 '22 02:01 amowu

Workaround:

This is reproducible for me when download is handled this way

location.href = link

However, changing it like this works fine

const iframeElement = document.createElement('iframe');
iframeElement.style.display = 'none';
iframeElement.src = link;
document.body.appendChild(iframeElement);

Note: might have issues with IE

iskathi avatar Jan 31 '22 14:01 iskathi

I am having the same issue and it feels like a bug, or at least Cypress is lacking the option to skip waiting for page loads... I think such an option would be much appreciated.

After I tried @sarja510's workaround

cy.window().document().then(function (doc) {
  doc.addEventListener('click', () => {
    setTimeout(function () { doc.location.reload() }, 5000)
  })
  cy.get('[ng-click="vm.export()"]').click()
})

(btw thanks for that – if it weren't for other difficulties in our SPA this would've worked) I found another "solution" that I wanted to share here in case it helps somebody else.

I ended up changing the anchor tags in question to have the properties

<a href={/link/to/file.ext} target="_blank" rel="noreferrer">Download</a>

so that clicking the link actually opens a separate browser tab.

This way Cypress acknowledges the "page load" and does not hang indefinitely. In the browsers we support (mainly chrome) this is still an ok user experience (when the sent file has appropriate headers like "content-disposition: attachment..."). The browser opens a new tab and closes it again as soon as the download proceeds.

So this seems to solve the problem for us and this way I didn't have to use the async-reload-workaround which caused problems with pending requests without a session.

Jay-Schneider avatar Feb 02 '22 16:02 Jay-Schneider