I was trying to validate zip file contents using adm-zip
and cypress
, but cypress throws out of memory error. The Zip file could contain .txt or .pdf or .ppt or .docx files. I would like to validate below in the zip file:
a) no of files
b) type of files
"cypress": "v12.8.1",
"adm-zip": "^0.5.10",
"path": "^0.12.7"
Note: Using Adm-zip from this https://www.npmjs.com/package/adm-zip
test.spec.js
import HelperFunctions from "../../../support/helperFunctions";
const helperFunctions = new HelperFunctions();
it('Download test', function () {
cy.get('button[type="submit"]').contains("Download").click({force:true});
helperFunctions.validateZip();
})
helperFunctions.js
validateZip () {
const downloadsFolder = Cypress.config('downloadsFolder')
const downloadedFilename = path.join(downloadsFolder, 'ComprehensionStrategyTeachingResourcePackSummarisingZipFile.zip')
// wait for the file to be fully downloaded by reading it (as binary)
// and checking its length
cy.readFile(downloadedFilename, 'binary', { timeout: 35000 }).should('have.length.gt', 300)
// unzipping and validating a zip file requires the direct access to the file system
// thus it is easier to perform the checks from the `setupNodeEvents` function in the Cypress configuration that runs in Node
// see the "on('task')" code in the `setupNodeEvents` function to see how we can read and validate a Zip file
cy.task('validateZipFile', downloadedFilename)
}
cypress.config.js
const AdmZip = require("adm-zip");
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
.....
on("task", {
validateZipFile: (filename) => {
return validateZipFile(filename);
},
});
return config;
},
baseUrl: "https://staging-qa.someurl.com/",
specPattern: "cypress/e2e/**/*.spec.{js,jsx,ts,tsx}",
},
})
function validateZipFile (filename) {
// now let's validate the downloaded ZIP file
// Tip: use https://github.com/cthackers/adm-zip to load and unzip the Zip contents
console.log('loading zip', filename)
const zip = new AdmZip(filename)
const zipEntries = zip.getEntries()
const names = zipEntries.map((entry) => entry.entryName).sort()
console.log('zip file %s has entries %o', filename, names)
// any other validations?
return null
}
If the main problem is memory, I would change the cy.readFile()
into a task, that way you don't read the whole file into Cypress memory.
Changes:
add a task that uses fs.statSync()
to get the file size in nodejs, which should be more memory-friendly than reading the file into Cypress browser memory
move path.join()
to the task as it's a native nodejs function
return a summary of whatever validations are performed (e.g the list of names in the zip) and assert validations in the test
Other than that, it all looks good.
cypress.config.js
const { defineConfig } = require('cypress')
const AdmZip = require("adm-zip");
const path = require('path')
const fs = require('fs')
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// .....
on('task', {
validateZipFile: filename => {
const downloadsFolder = config.downloadsFolder
return validateZipFile(path.join(downloadsFolder, filename))
},
getZipFileSize: filename => {
const downloadsFolder = config.downloadsFolder
const stats = fs.statSync(path.join(downloadsFolder, filename))
return stats.size
}
})
return config
},
},
})
function validateZipFile(filename) {
const zip = new AdmZip(filename)
const zipEntries = zip.getEntries()
const names = zipEntries.map(entry => entry.entryName).sort()
return names
}
Test
function validateZip () {
const downloadedFilename = 'sample-large-zip-file.zip'
cy.task('getZipFileSize', downloadedFilename)
.should('eq', 5216156)
cy.task('validateZipFile', downloadedFilename)
.should('deep.eq', ['sample-mpg-file.mpg'])
}
it('Download test', function () {
cy.get('button[type="submit"]')
.contains('Download')
.click({ force: true })
validateZip()
})