Cypress: In-browser file download support

Created on 22 Nov 2017  路  66Comments  路  Source: cypress-io/cypress

Current behavior:

In Electron, when an anchor is clicked that downloads a file from the server, a "Save" dialog is shown thus preventing the rest of the test case from completing / succeeding. No dialog is shown in Chrome, at least currently, but this appears to be just because that's Chrome's default behaviour.

Furthermore, there is no way of specifying the desired location of file downloads.

Desired behavior:

  1. No "Save" dialog should be ever shown.
  2. Not as crucial (i.e. with rather easy workaround in the CI), but we should be able to configure browser (both Chrome and Electron, and any browsers supported in the future) with the location where files should be downloaded.

This should work both for files downloaded from the server (with Content-Disposition HTTP header), as well as for files downloaded using in-browser Blob + dynamically generated anchor approach.

How to reproduce:

Given any site that contains an <a href="">...</a> pointing to a file served with Content-Disposition header, use a test script similar to the one posted below:

Test code:

describe('Lorem', function() {
  it('Ipsum', function() {
    cy.visit("https://localhost")
      .get("a.download-link").click()
      // This blocks in Electron because of the "Save" popup.
      .readFile("/Users/kls/Downloads/file.txt")
      .then(function() {
         // Do something with the file.
      });
  })
})

Additional Info (images, stack traces, etc)

This functionality is needed in cases where it is not possible to verify validity of the download using other methods suggested in the FAQ:

  • When downloaded file is dynamically generated on the server based on a data that browser sends over to it, in case when this data is sensitive and cannot be sent over in the file URL. Imagine a file path such as https://bank/transaction-history/34964483209802/pdf, where 34964483209802 is a credit card number. This is unacceptable from the security / compliance perspective, because HTTP URL's are oftentimes logged in proxies or web servers. One solution is to send sensitive data over secure comms, i.e. WebSockets, just after user clicks the anchor. But this makes it impossible to just look at URL and issue cy.request().
  • When downloaded file is dynamically generated in the browser using a Blob + transient <a> with data URI technique, in which case no request is made to the server at all.
5锔忊儯 ready for work native events feature

Most helpful comment

@kutlaykural Sorry for the late response, I was on vacation.

Yes, I did solve this problem in a sufficient way, at least for our needs.

1. Files that depend on more than URL to generate

For the files which are being generated on the backend based on a parameters supplied by the frontend via means other than URL itself (e.g. over an out-of-band WebSockets connection), this approach works:

<a id="download-file" href="/file?download-id=ABCDEFGH">Download</a>

<script>
  document.getElementById('download-file').onclick = function(event) {
    // In test, prevent the browser from actually downloading the file.
    if (window.Cypress) {
      event.preventDefault();
    }

    // But let it do all other things, most importantly talk to the backend
    // out-of-band to configure the download.
    setupFileOverWebSockets('ABCDEFGH');
  }
</script>

Then, in the test, I would do:

cy.get('a').click().then((anchor) => {
  const url = anchor.prop('href');
  // cy.request() will work, because web app did talk to the backend out-of-band.
  cy.request(url).then(/* do something, e.g. assert */);
});

2. Files generated in the browser

This technique involves using a temporary anchor element, which has a href set to a value obtained from URL.createObjectURL(). I think the following should work:

    <button id="test">Download file!</button>
    <script>
      const button = document.getElementById('test');
      button.addEventListener('click', () => {
        const blob = new Blob(['lorem ipsum dolor sit amet']);
        const anchor = document.createElement('a');
        const url = URL.createObjectURL(blob);

        anchor.download = 'test.txt';
        anchor.href = url;
        document.body.appendChild(anchor);

        if (window.Cypress) {
          // Do not attempt to actually download the file in test.
          // Just leave the anchor in there. Ensure your code doesn't
          // automatically remove it either.
          return;
        }

        anchor.click();
      });
    </script>

And the test:

  it.only('asserts in-browser generated file', () => {
    // Click the button to start downloading the file. The web app
    // will detect it's running within Cypress, and will create 
    // a temporary anchor, will set a correct href on it, but it won't
    // click it and won't attempt to remove it.
    cy.get('#test').click();

    // Obtain a reference to that temporary anchor.
    cy.get('a[download]')
      .then((anchor) => (
        new Cypress.Promise((resolve, reject) => {
          // Use XHR to get the blob that corresponds to the object URL.
          const xhr = new XMLHttpRequest();
          xhr.open('GET', anchor.prop('href'), true);
          xhr.responseType = 'blob';

          // Once loaded, use FileReader to get the string back from the blob.
          xhr.onload = () => {
            if (xhr.status === 200) {
              const blob = xhr.response;
              const reader = new FileReader();
              reader.onload = () => {
                // Once we have a string, resolve the promise to let
                // the Cypress chain continue, e.g. to assert on the result.
                resolve(reader.result);
              };
              reader.readAsText(blob);
            }
          };
          xhr.send();
        })
      ))
      // Now the regular Cypress assertions should work.
      .should('equal', 'lorem ipsum dolor sit amet');
  })

In summary, I use the first approach in our test already and it works well. I don't test the in-browser generated files yet using Cypress (we have legacy Selenium suite for that), but I quickly tested the approach I described here and it seems to be working.

I'd love if Cypress would let us just download a file and assert on its contents, but in the meantime those approaches provide enough coverage for most, if not all, needs.

All 66 comments

Related: #433 #311 #4675

@kamituel did you solve this problem?
can you share your solution?

@kutlaykural Sorry for the late response, I was on vacation.

Yes, I did solve this problem in a sufficient way, at least for our needs.

1. Files that depend on more than URL to generate

For the files which are being generated on the backend based on a parameters supplied by the frontend via means other than URL itself (e.g. over an out-of-band WebSockets connection), this approach works:

<a id="download-file" href="/file?download-id=ABCDEFGH">Download</a>

<script>
  document.getElementById('download-file').onclick = function(event) {
    // In test, prevent the browser from actually downloading the file.
    if (window.Cypress) {
      event.preventDefault();
    }

    // But let it do all other things, most importantly talk to the backend
    // out-of-band to configure the download.
    setupFileOverWebSockets('ABCDEFGH');
  }
</script>

Then, in the test, I would do:

cy.get('a').click().then((anchor) => {
  const url = anchor.prop('href');
  // cy.request() will work, because web app did talk to the backend out-of-band.
  cy.request(url).then(/* do something, e.g. assert */);
});

2. Files generated in the browser

This technique involves using a temporary anchor element, which has a href set to a value obtained from URL.createObjectURL(). I think the following should work:

    <button id="test">Download file!</button>
    <script>
      const button = document.getElementById('test');
      button.addEventListener('click', () => {
        const blob = new Blob(['lorem ipsum dolor sit amet']);
        const anchor = document.createElement('a');
        const url = URL.createObjectURL(blob);

        anchor.download = 'test.txt';
        anchor.href = url;
        document.body.appendChild(anchor);

        if (window.Cypress) {
          // Do not attempt to actually download the file in test.
          // Just leave the anchor in there. Ensure your code doesn't
          // automatically remove it either.
          return;
        }

        anchor.click();
      });
    </script>

And the test:

  it.only('asserts in-browser generated file', () => {
    // Click the button to start downloading the file. The web app
    // will detect it's running within Cypress, and will create 
    // a temporary anchor, will set a correct href on it, but it won't
    // click it and won't attempt to remove it.
    cy.get('#test').click();

    // Obtain a reference to that temporary anchor.
    cy.get('a[download]')
      .then((anchor) => (
        new Cypress.Promise((resolve, reject) => {
          // Use XHR to get the blob that corresponds to the object URL.
          const xhr = new XMLHttpRequest();
          xhr.open('GET', anchor.prop('href'), true);
          xhr.responseType = 'blob';

          // Once loaded, use FileReader to get the string back from the blob.
          xhr.onload = () => {
            if (xhr.status === 200) {
              const blob = xhr.response;
              const reader = new FileReader();
              reader.onload = () => {
                // Once we have a string, resolve the promise to let
                // the Cypress chain continue, e.g. to assert on the result.
                resolve(reader.result);
              };
              reader.readAsText(blob);
            }
          };
          xhr.send();
        })
      ))
      // Now the regular Cypress assertions should work.
      .should('equal', 'lorem ipsum dolor sit amet');
  })

In summary, I use the first approach in our test already and it works well. I don't test the in-browser generated files yet using Cypress (we have legacy Selenium suite for that), but I quickly tested the approach I described here and it seems to be working.

I'd love if Cypress would let us just download a file and assert on its contents, but in the meantime those approaches provide enough coverage for most, if not all, needs.

Download

@kamituel
Can you please tell me where should the above piece of code be written?

I tried the in 'test portion' of the code in the cypress test, and yet I still saw the 'save pop up'

@Shubha-Alvares The code you posted:

// '#download-file' here is an anchor that user clicks to download a file.
// It has to be the correct DOM element in order for the code to cancel
// the correct 'event' object.
document.getElementById('download-file').onclick = function(event) {

  // ...

  // In test, prevent the browser from actually downloading the file.
  if (window.Cypress) {
    event.preventDefault();
  }

  // ...

});

If you're seeing the popup, it might mean that:

  • you added the if (window.Cypress) { ... } guard in the incorrect event handler.
  • the event you invoked event.preventDefault() on is not the correct event object.
  • you're running your web app outside of Cypress (and hence window.Cypress is unset).

Hard to be more definitive not seeing your code. But in general, this approach should work as long as you manage to cancel .preventDefault() the correct event. In fact, I'm using this approach in our production app for months now with no issues.

Just a note on solution 1 by @kamituel:

cy.get('a').click().then((anchor) => {
  const url = anchor.prop('href');
  // cy.request() will work, because web app did talk to the backend out-of-band.
  cy.request(url).then(/* do something, e.g. assert */);
});

_...didn't work for me, BUT using .attr() instead of .props() did:_

cy.get('a').click().then((anchor) => {
  const url = anchor.attr('href');
  // cy.request() will work, because web app did talk to the backend out-of-band.
  cy.request(url).then(/* do something, e.g. assert */);
});

Thank you @kamituel! You solved a blocker for me.

I apologize if this is obvious but based on @kamituel solution above, are we able to change the save location when cypress downloads a file?

@natejcho No, because at no point the browser actually downloads the file using the native "download manager". I explicitly prevent that in test (when window.Cypress is set).

That's in fact the main reason the two approaches I described work. I prevent the browser from actually downloading the file, and instead I download the file, store its contents in a variable, and assert that (in the test code).

@kamituel I realized this after playing around with your code more.

But I solved my unique issue in which I wanted cypress to download a file and place it in a specific location.

I used your solution so the test could receive a base64 string. Then created a plugin to handle the encoding and writing the file to a directory. Cypress plugins run in the node and I am able to utilize the fs library and write files at the project root level.

See [https://github.com/cypress-io/cypress/issues/2029] for writing the plugin

@kamituel I realized this after playing around with your code more.

But I solved my unique issue in which I wanted cypress to download a file and place it in a specific location.

I used your solution so the test could receive a base64 string. Then created a plugin to handle the encoding and writing the file to a directory. Cypress plugins run in the node and I am able to utilize the fs library and write files at the project root level.

See [https://github.com//issues/2029] for writing the plugin

Hello, natejcho

I want to implement the same way. I want to get the response of the file thats require to download.
it can be word/pdf or excel file.
Want to validate the downloaded content. Thought the same way as you have written, but its not working. Could you please describe more on this or share a prototype of your code.(way of implementation).

waiting for your reply.

Thanks

I have used cy.request to get the response of the file. Which I am getting successfully. Now, How to pass the response to the nodejs plugin is the problem. I have tried the below code but its not working.

cy.request(href).then((response) => {
  expect(response.status).to.equal(200);
  expect(response.body).not.to.null;
  cy.exec("node cypress/support/Core/Parser/PDFParser.js " + response.body, {failOnNonZeroExit: false}).then((result: any) => {
             console.log(result);
              });
});

For a future solution to this problem in Cypress itself: Once #4628 is merged, we'll have access to the Chrome DevTools Protocol, which has these 2 functions:

Cypress could set the downloadBehavior to deny (so any request to download a file isn't actually downloaded), and then listen on downloadWillBegin to catch any requests for file downloads, allowing them to be captured & tested inside of Cypress.

Maybe the API could look something like this:

Cypress.on('download:will:begin', (url) => {
    // cy.request(url) could be used here to assert on contents?
    // potential problem: we don't have access to the request body or headers
    // used to make this download happen
})

To add on top of this. I'd like to make a feature request

getDownload or downloadToRoot. The naming convention isn't important to me, but it would save a download to the root of cypress project. I commented above how I've already achieved this in my application. I would be happy to open an MR for it as well.

This issue has lots of activity and been mentioned in many different issues. Which I think indicates a good need for it

For a future solution to this problem in Cypress itself: Once #4628 is merged, we'll have access to the Chrome DevTools Protocol, which has these 2 functions:

Cypress could set the downloadBehavior to deny (so any request to download a file isn't actually downloaded), and then listen on downloadWillBegin to catch any requests for file downloads, allowing them to be captured & tested inside of Cypress.

Maybe the API could look something like this:

Cypress.on('download:will:begin', (url) => {
  // cy.request(url) could be used here to assert on contents?
  // potential problem: we don't have access to the request body or headers
  // used to make this download happen
})

Hello.
Any news from this feature?

Hello Any news to how to manage download in cypress?
Folder destination and popup?

Hello Any news to how to manage download in cypress?
Folder destination and popup?

Sooooo. Cypress is a wild forest in which I overestimated my navigating abilities. I don't have the time needed to finish an MR for the feature. But i'd be happy to share my custom solution:

Copy the second approach posted by @kamituel

2. Files generated in the browser

This technique involves using a temporary anchor element, which has a href set to a value obtained from URL.createObjectURL(). I think the following should work:

    <button id="test">Download file!</button>
    <script>
      const button = document.getElementById('test');
      button.addEventListener('click', () => {
        const blob = new Blob(['lorem ipsum dolor sit amet']);
        const anchor = document.createElement('a');
        const url = URL.createObjectURL(blob);

        anchor.download = 'test.txt';
        anchor.href = url;
        document.body.appendChild(anchor);

        if (window.Cypress) {
          // Do not attempt to actually download the file in test.
          // Just leave the anchor in there. Ensure your code doesn't
          // automatically remove it either.
          return;
        }

        anchor.click();
      });
    </script>

And the test:

  it.only('asserts in-browser generated file', () => {
    // Click the button to start downloading the file. The web app
    // will detect it's running within Cypress, and will create 
    // a temporary anchor, will set a correct href on it, but it won't
    // click it and won't attempt to remove it.
    cy.get('#test').click();

    // Obtain a reference to that temporary anchor.
    cy.get('a[download]')
      .then((anchor) => (
        new Cypress.Promise((resolve, reject) => {
          // Use XHR to get the blob that corresponds to the object URL.
          const xhr = new XMLHttpRequest();
          xhr.open('GET', anchor.prop('href'), true);
          xhr.responseType = 'blob';

          // Once loaded, use FileReader to get the string back from the blob.
          xhr.onload = () => {
            if (xhr.status === 200) {
              const blob = xhr.response;
              const reader = new FileReader();
              reader.onload = () => {
                // Once we have a string, resolve the promise to let
                // the Cypress chain continue, e.g. to assert on the result.
                resolve(reader.result);
              };
              reader.readAsText(blob);
            }
          };
          xhr.send();
        })
      ))
      // Now the regular Cypress assertions should work.
      .should('equal', 'lorem ipsum dolor sit amet');
  })

This will make the download consumable by cypress

Then use this approach from [/issues/2029] by @WesleySSmith:

As a workaround, I found that I could use a custom plugin to perform the download. In my case, I was trying to download an xlsx file, but I think a similar approach could be used to test PDF files or just save the files after downloading them.

Added via npm:

  • node-xlsx (specific to xlsx parsing)
  • request (to make https request)

plugins/index.js:

on('task', {
    // args must be {url: "<url>, cookies: [{name: "cookie1", value: "value1"}, {name: "cookie2", value: "value2"}, ...]"}
    parseXlsx(args) {
      const cookieheader = args.cookies.map(e => e.name + "=" + e.value).join(";");
      return new Promise((resolve, reject) => {
        const r = request({url: args.url, encoding:null, headers: {Cookie: cookieheader}}, function(err, res, body) {
          if (!res) {
            return reject(new Error("No response"));
          }
          if (res.statusCode !== 200) {
            return reject(new Error("Bad status code: " + res.statusCode));
          }
          const sheet = xlsx.parse(body);
          console.log(JSON.stringify(sheet));
          resolve(sheet);
        });
      });
    }
  });

support/commands.js:

Cypress.Commands.add("parseXlsx", (url) => {
    return cy.getCookies().then(cookies => {
        return cy.task('parseXlsx', {url: url, cookies: cookies });
    });
});

In my test file:

// Call parseXlsx and verify that the export is as expected
  cy.parseXlsx(exportUrl).should(data => {
          expect(data).to.have.xlsSheetName("Payments");
          expect(data).to.have.xlsSheetRowCell(0,0,0,'Reference #');
      });

You will have to play around with the encoding, and how you detect cypress. I set an env variable and check for that.

@kamituel
First of all thank you so much for the updates here. This is really useful as I am new to cypress.
I am facing the same issue while downloading a file using cypress.

<a id="download-file" href="/file?download-id=ABCDEFGH">Download</a>

<script>
  document.getElementById('download-file').onclick = function(event) {
    // In test, prevent the browser from actually downloading the file.
    if (window.Cypress) {
      event.preventDefault();
    }

    // But let it do all other things, most importantly talk to the backend
    // out-of-band to configure the download.
    setupFileOverWebSockets('ABCDEFGH');
  }
</script>

I tried to implement this solution you provided but facing an error.
Property 'Cypress' does not exist on type 'Window & typeof globalThis'.
Could you please clarify why this error message is showing up?

@CuriousSoul230 Hard to tell without seeing more of the code you're running. The particular error message you're getting though...:

Property 'Cypress' does not exist on type 'Window & typeof globalThis'.

... it suggests you're using TypeScript. Is that the case? If so, then you need to extent a window interface to include the Cypress property you refer to:

interface Window {      // New line
  Cypress: any          // New line
}                       // New line

if (window.Cypress) {
    event.preventDefault();
}

Ideally you'd put that interface piece it into some .d.ts file.

I cant find any .ts file :(
could you please confirm where I can find it?

@CuriousSoul230 I wouldn't know that, I'm not able to see your whole project.

@kamituel
First of all thank you so much for the updates here. This is really useful as I am new to cypress.
I am facing the same issue while downloading a file using cypress.

<a id="download-file" href="/file?download-id=ABCDEFGH">Download</a>

<script>
  document.getElementById('download-file').onclick = function(event) {
    // In test, prevent the browser from actually downloading the file.
    if (window.Cypress) {
      event.preventDefault();
    }

    // But let it do all other things, most importantly talk to the backend
    // out-of-band to configure the download.
    setupFileOverWebSockets('ABCDEFGH');
  }
</script>

I tried to implement this solution you provided but facing an error.
Property 'Cypress' does not exist on type 'Window & typeof globalThis'.
Could you please clarify why this error message is showing up?

I don't use window.Cypress to check. I actually set an env variable when I run my frontend for Cypress testing. At the end of the day you just need a branch specific to Cypress downloads.

You could even use localStorage

I managed to have it working on Chrome/Chromium in non-headless mode, without the need to edit the application's source code (as in my app I'm unable to do it because file download is handled by an external library):

// plugins/index.js

const fs = require('fs');
const path = require('path');

const downloadsDirectory = path.join(__dirname, '..', 'downloads');

const cleanDownloadsDirectory = () => {
  fs.rmdirSync(downloadsDirectory, { recursive: true });
  return null;
};

const setUpDownloadsDirectory = (browser, options) => {
  cleanDownloadsDirectory();

  if (browser.family === 'chromium' && browser.name !== 'electron') {
    options.preferences.default.profile = { default_content_settings: { popups: 0 } };
    options.preferences.default.download = { default_directory: downloadsDirectory };

    return options;
  }

  // not-tested on FF
  if (browser.family === 'firefox') {
    options.preferences['browser.download.dir'] = downloadsDirectory;
    options.preferences['browser.download.folderList'] = 2;
    options.preferences['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv';

    return options;
  }
};

module.exports = on => {
  on('before:browser:launch', setUpDownloadsDirectory);
  on('task', {
    cleanDownloadsDirectory,
  });
};

and in the test:

describe('Download file', () => {
  beforeEach(() => {
    cy.task('cleanDownloadsDirectory')
      .visit('/something');
  });

  it('should export data to the correct file', () => {
    // given
    const expectedFileName = 'some_file.xlsx';

    // when
    cy.get('.download-button')
      .click()

      // then
      .readFile(`cypress/downloads/${expectedFileName}`, 'base64').then(downloadedFile => {
        // some assertions
      });
  });
});

Unfortunately, it does not work under Electron or headless Chrome (no file is saved) so I cannot run this on CI. It would be good to have any way to force Electron to save the file without prompt or have some workaround for headless Chrome.

@TomaszG thanks this is super useful. I'm guessing popups: 0 is supposed to disable the "site is trying to download multiple files" warning, but that didn't work for me. This does however:

        options.preferences.default.profile = {
            content_settings: {
                exceptions: {
                    automatic_downloads: {
                        '*': { setting: 1 }
                    }
                }
            }
        };

https://medium.com/@VivekNayyar/e2e-testing-of-excel-downloads-with-cypress-d6e46ccdc232
https://dev.to/viveknayyar/e2e-testing-of-excel-downloads-with-cypress-21fb

This might be useful for someone landing here.

@vivek12345 could you confirm that it works also with headless chrome or with electron? Looking at implementation it's very similar to the one which I have posted before where I wasn't able to run the same test with headless chrome (file was not downloaded).

@TomaszG no unfortunately on headless mode the download still won't happen.
I will add a disclaimer to the article. Thanks for pointing it out.

Doing simple stuff, clicking on a button in UI聽(web application), that will export(download) a file-聽.xlsx file in the download folder, same stuff when I am trying to do with cypress,cy.get ('css_id').click聽, and running through electron it prompts me system window to save the file聽,how to handle this stuff as my test cases is incomplete without downloading it聽?

Tried with each solution given in git for this problem , downloaded plugin,made changes in index file in cypress ,but nothing helped.

Trying to do the same stuff and test is being stuck at waiting for page to load after click in chrome browser. Can someone suggest any workarounds without changing the application code?

Following is the test code running it on chrome browser:

describe('zip download', () => {
  it('download a file', () => {
    cy.server();
    cy.route('GET', 'https://send.firefox.com/api/download/*').as('download');
    cy.visit('https://send.firefox.com/download/abae004e811492ca/#ySq5RqyPlf3eti4fDVqkDQ');
    cy.wait(1500);
    cy.get('#download-btn').click().then( ()=> {
        cy.wait('@download').its('status').should('eq', 200);
    });

  });
});

Any update?

Bump:

P.S. I'm using npm "file-saver": "^2.0.2",, so I don't even have a button. And I'd like to read the content of the file. Solutions like HTTP GET the content by the URL will never work for me...

Perfect timing...I'm also using file-saver.

Bump:

P.S. I'm using npm "file-saver": "^2.0.2",, so I don't even have a button. And I'd like to read the content of the file. Solutions like HTTP GET the content by the URL will never work for me...

So just adding dependency "file-saver": "^2.0.2" in package.json will stop the prompts of the system to save the file, and eventually it will directlty save the file in system download folder?

nothing to add or modify at at script level?

Bump:
P.S. I'm using npm "file-saver": "^2.0.2",, so I don't even have a button. And I'd like to read the content of the file. Solutions like HTTP GET the content by the URL will never work for me...

So just adding dependency "file-saver": "^2.0.2" in package.json will stop the prompts of the system to save the file, and eventually it will directlty save the file in system download folder?

nothing to add or modify at at script level?

any update?

Any updates about the situation ? I am trying to run cypress version "4.7.0" in headless chrome, but it does not download anything. It works pretty well in ui mode but in order to make this part of our CI pipeline process I need headless version running.

@kamituel Hi, sorry to ask again this question but it seems it has not been answered yet. I would like to implement your second solution to get file content (when it's generated in browser and using Electron, so i can't force download options to directly get the file where i want).

Where should i put this code you wrote ?

    <button id="test">Download file!</button>
    <script>
      const button = document.getElementById('test');
      button.addEventListener('click', () => {
        const blob = new Blob(['lorem ipsum dolor sit amet']);
        const anchor = document.createElement('a');
        const url = URL.createObjectURL(blob);

        anchor.download = 'test.txt';
        anchor.href = url;
        document.body.appendChild(anchor);

        if (window.Cypress) {
          // Do not attempt to actually download the file in test.
          // Just leave the anchor in there. Ensure your code doesn't
          // automatically remove it either.
          return;
        }

        anchor.click();
      });
    </script>

Should I inject this in current page ? how ? (i can't modify the code of the app itself)
Thanks for your help.
Regards,

@aubertaa This is the code that downloads the file - the application code, not a test code.

The crucial piece is the if (window.Cypress) return part. It will prevent the browser from actually downloading the file, but will leave the dynamically-created <a> element with the data URI in the DOM.

In your test you will be then able to find this <a> and check if the data URI is correct.

Seems like they gave up on this one. It was opened in 2017.

I can tell you how I have things set up to support downloads in the application via setting