'Cypress - How can I verify if the downloaded file contains name that is dynamic?

In cypress, the xlsx file I am downloading always starts with lets say "ABC" and then some dynamic IDs. How can I verify if the file is downloaded successfully and also contains that dynamic name? Secondly, what if the downloaded file is like "69d644353f126777.xlsx" then how can i verify that the file is downloaded when everything in the name is dynamic.

Thanks in advance.



Solution 1:[1]

One way that suggests itself is to query the downloads folder with a task,

/cypress/plugins/index.js

const fs = require('fs');

on('task', {
  downloads:  (downloadspath) => {
    return fs.readdirSync(downloadspath)
  }
})

test

cy.task('downloads', 'my/downloads/folder').then(before => {

  // do the download

  cy.task('downloads', 'my/downloads/folder').then(after => {
    expect(after.length).to.be.eq(before.length +1)  
  })
})

If you can't direct the downloads to a folder local to the project, provide a full path. Node.js (i.e Cypress tasks) has full access to the file system.


To get the name of the new file, use a filter and take the first (and only) item in the result.

const newFile = after.filter(file => !before.includes(file))[0]

 

Solution 2:[2]

Maybe this will works but this also requires a filename to be assert.Write this code in index.js

on('task', {
        isExistPDF(PDFfilename, ms = 4000) {
          console.log(
            `looking for PDF file in ${downloadDirectory}`,
            PDFfilename,
            ms
          );
          return hasPDF(PDFfilename, ms);
        },
      });

Now add custom command in support/commands.js

Cypress.Commands.add('isDownloaded', (selectorXPATH, fileName) => {
  //click on button
  cy.xpath(selectorXPATH).should('be.visible').click()
  //verify downloaded file
  cy.task('isExistPDF', fileName).should('equal', true)
})

Lastly write this code in your logic area

verifyDownloadedFile(fileName) {
    //Clear downloads folder
    cy.exec('rm cypress/downloads/*', {
      log: true,
      failOnNonZeroExit: false,
    })
    cy.isDownloaded(this.objectFactory.exportToExcelButton, fileName)
  }

and call this function in your testcase

Solution 3:[3]

I ended up using something similar to @user14783414.
However I keep getting that the downloads' folder length was 0. I then added an cy.wait() which solved the issue.

cy.task('downloads', 'my/downloads/folder').then(before => {
  // do the download
  }).then(() => {
    cy.wait(500).then(() => {
      cy.task('downloads', 'my/downloads/folder').then(after => {
    expect(after.length).to.be.eq(before.length +1)  
      })
    })
  })
})

Solution 4:[4]

Another approach is to leverage Nodes fs.watch(...) API and to define a plugin task which waits for a new download to be available and returns the filename:

/cypress/plugins/index.js

const fs = require('fs');
module.exports = (on, config) => {
  on('task', {
    getDownload: () => {
      const downloadsFolder = config['downloadsFolder'];
      return new Promise((resolve, reject) => {
        const watcher = fs.watch(downloadsFolder, (eventType, filename) => {
          if (eventType === 'rename' && !filename.endsWith('.crdownload')) {
            resolve(filename);
            watcher.close();
          }
        });
        setTimeout(reject, config.taskTimeout); // Or another timeout if desired
      });
    },
  });
};

And then it is fairly easily used within a test spec as follows:

/sometest.spec.js

it('downloads a file', () => {
  cy.get(downloadButtonSelector).click();
  cy.task('getDownload').then(fileName => {
    // do something with your newly downloaded file!
    console.log('Downloaded file:', fileName);
  });
});

Now technically there may be a bit of a race condition if the file is downloaded extremely quickly and the file exists on disk before the watcher begins, but in my testing - even with relatively small files and fast network speed - I have never observed this.

Solution 5:[5]

For the solution of Nicholas, in firefox, the '.crdownload' doesn't exist so we need to add a condition on the '.part' :

if (eventType === 'rename' && !filename.endsWith('.crdownload') && !filename.endsWith('.part'))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Abdullah Sohail Yaqoob
Solution 3 iff
Solution 4 nicholas
Solution 5 user18780584