15

I have a little problem with trying to check if a file is downloaded.

Button click generates a PDF file and starts its download.

I need to check if it works.

Can Cypress do this?

BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
Dominik Skála
  • 793
  • 4
  • 12
  • 30
  • 2
    There was a [similar question already asked here](https://stackoverflow.com/questions/53627113/verify-the-data-of-the-downloaded-file-pdf-word-excel-using-cypress-commands). This should help you :) – voy Mar 04 '20 at 09:34

2 Answers2

7

cypress/plugins/index.js

    const path = require('path');
    const fs = require('fs');
    
    const downloadDirectory = path.join(__dirname, '..', 'downloads');
    
    const findPDF = (PDFfilename) => {
      const PDFFileName = `${downloadDirectory}/${PDFfilename}`;
      const contents = fs.existsSync(PDFFileName);
      return contents;
    };
    
    const hasPDF = (PDFfilename, ms) => {
      const delay = 10;
      return new Promise((resolve, reject) => {
        if (ms < 0) {
          return reject(
            new Error(`Could not find PDF ${downloadDirectory}/${PDFfilename}`)
          );
        }
        const found = findPDF(PDFfilename);
        if (found) {
          return resolve(true);
        }
        setTimeout(() => {
          hasPDF(PDFfilename, ms - delay).then(resolve, reject);
        }, delay);
      });
    };
    
    module.exports = (on, config) => {
      require('@cypress/code-coverage/task')(on, config);
      on('before:browser:launch', (browser, options) => {
        if (browser.family === 'chromium') {
          options.preferences.default['download'] = {
            default_directory: downloadDirectory,
          };
          return options;
        }
        if (browser.family === 'firefox') {
          options.preferences['browser.download.dir'] = downloadDirectory;
          options.preferences['browser.download.folderList'] = 2;
          options.preferences['browser.helperApps.neverAsk.saveToDisk'] =
            'text/csv';
          return options;
        }
      });
    
      on('task', {
        isExistPDF(PDFfilename, ms = 4000) {
          console.log(
            `looking for PDF file in ${downloadDirectory}`,
            PDFfilename,
            ms
          );
          return hasPDF(PDFfilename, ms);
        },
      });
    
      return config;
    };

integration/pdfExport.spec.js

    before('Clear downloads folder', () => {
       cy.exec('rm cypress/downloads/*', { log: true, failOnNonZeroExit: false });
    });
        
    it('Should download my PDF file and verify its present', () => {
        cy.get('ExportPdfButton').click();
        cy.task('isExistPDF', 'MyPDF.pdf').should('equal', true);
    });
Nate Anderson
  • 18,334
  • 18
  • 100
  • 135
abdp
  • 317
  • 4
  • 15
  • 4
    When you shared code snippet, please try to add also explanation – Yunus Temurlenk Jul 08 '20 at 05:59
  • 2
    @YunusTemurlenk I usually agree, but this snippet is great and having a test is the explanation. – Ruan Mendes Feb 25 '21 at 23:19
  • 1
    Nice example to check if the PDF was downloaded; i.e. if the file exists. Cypress has a similar code (using `cy.task`) to show how to ["Read a file that might not exist"](https://docs.cypress.io/api/commands/task#Read-a-file-that-might-not-exist). Also consider the function [`cy.readFile(...)` if you're interested in reading](https://docs.cypress.io/api/commands/readfile). Finally, [here's another SO example that uses `cy.task`](https://stackoverflow.com/questions/53627113/verify-the-data-of-the-downloaded-file-pdf-word-excel-using-cypress-commands), i.e. for assertions re: file content – Nate Anderson Jan 21 '22 at 04:54
  • Even [this library seems like it uses a similar approach](https://github.com/elaichenkov/cy-verify-downloads) – Nate Anderson Jan 21 '22 at 05:29
5

I would suggest you to have a look to the HTTP response body. You can get the response with cy.server().route('GET', 'url').as('download') (check cypress documentation if you don't know these methods).

and catch the response to verify the body is not empty:

cy.wait('@download')
    .then((xhr) => {
        assert.isNotNull(xhr.response.body, 'Body not empty')
    })

Or if you have a popup announcing success when the download went successfully, you can as well verify the existence of the popup:

cy.get('...').find('.my-pop-up-success').should('be.visible')

Best,

EDIT

Please note cy.server().route() may be deprecated:

cy.server() and cy.route() are deprecated in Cypress 6.0.0. In a future release, support for cy.server() and cy.route() will be removed. Consider using cy.intercept() instead.

According to the migration guide, this is the equivalent: cy.intercept('GET', 'url').as('download')

Nate Anderson
  • 18,334
  • 18
  • 100
  • 135
François
  • 1,793
  • 14
  • 19
  • 2
    I don't think the `cy.server().route()` approach will work because a file download is not a `GET` request. – Ed Hollinghurst Aug 25 '20 at 13:46
  • 2
    Thanks François, It worked like charm. Before triggering download I am calling a GET api for getting CSV usage, So this approach helped to ensure that response is valid. – Kishor May 07 '21 at 04:33
  • Sometimes a download comes from a GET request that responds with a file, but not always. Sometimes the Blob can be generated entirely from the frontend and downloaded (like generating an xlsx file, for example). @abdp's answer is better in general. – Pedro A Aug 11 '23 at 19:30