I have a test that opens a windows pop-up to save the users personal data. Here I want to click "OK"
I tried to use cy.go('forward') but that does not work for windows pop ups.
Change the download directory of files downloaded during Cypress tests.
Change download directory cypress doc
// cypress/plugins/index.js
const path = require('path')
module.exports = (on) => {
on('before:browser:launch', (browser, options) => {
const downloadDirectory = path.join(__dirname, '..', 'downloads')
if (browser.family === 'chromium' && browser.name !== 'electron') {
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
// needed to prevent download prompt for text/csv files.
options.preferences['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv'
return options
}
})
}
Window doesn't open, and the file is downloaded directly. (It doesn't work for Electron browser)
add pictures to the fixtures folder
Install file-upload via powershell npm install cypress-file-upload
add to yout commands.js : import ‘cypress-file-upload’
add to your code:
cy.xpath('//*[#id="FileUpload"]')
.attachFile('/picturename')
Related
I have to download a excel file lets say "someData.xlsx" during test execution meanwhile before downloading also have to put a check over download folder if "someData.xlsx" exist in download folder delete it before downloading the newly updated file. could someone explain how to achieve this ?
I tried this but getting fs.readdirSync is not a function
fs.readdirSync('./downloads').forEach((file) => {
fs.unlinkSync(`./downloads/${file}`);
});
install cypress-delete-downloads-folder by
npm i -D cypress-delete-downloads-folder
in plugins/index.js
const fs = require("fs");
const { removeDirectory } = require('cypress-delete-downloads-folder');
module.exports = (on, config) => {
//task to check if file exist
on("task", {
isFileExist( filePath ) {
return new Promise((resolve, reject) => {
try {
let isExists = fs.existsSync(filePath)
resolve(isExists);
} catch (e) {
reject(e);
}
});
}
});
//to remove directory
on('task', { removeDirectory });
}
in support/commands.js
require('cypress-delete-downloads-folder').addCustomCommand();
in your test spec file
const path = require('path');
describe('check for file in download folder and if exist delete', () => {
it('delete download folder', () => {
cy.task("isFileExist", { fileName: `.${path.sep}downloads${path.sep}fileName.xlsx`}).then(() => {
cy.deleteDownloadsFolder()
});
You can create a script in "scripts" section of "Package.json" like below:
"clear": "del /f cypress\\results\\*.xlsx"
which will forcefully delete the XLSX files of "cypress\results\" folder. Now, execute this before running your tests.
Refer image as I've used for deleting the JSON files in the respective folder.
I'm currently adding a browser extension through a folder like so:
module.exports = (on, config) => {
on('before:browser:launch', (browser, launchOptions) => {
const extensionFolder = 'some/local/path';
if (browser.family === 'chromium'){
launchOptions.args.push(`--load-extension=${extensionFolder}`)
return launchOptions
}
})
}
which works fine, the extension is loaded onto the browser.
Is there a way to have it automatically running as well from the start, not just loaded on?
If that makes sense ...
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.
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]
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
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)
})
})
})
})
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.
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'))
I am using Cypress as my user interface test automation framework.
Currently my folder structure for spec file (logical organization of test files) is:
~/myAccount/header/header.spec.js
~/myAccount/footer/footer.spec.js
~/myAccount/mainTabs/home.spec.js
and so on...
Now when I configure my screenshot folder in cypress.json to screenshots and save screenshots of failed test cases, cypress internally creates a folder structure inside screenshots folder. For instance if a test fails in footer.spec.js, it saves the screenshot in
~/screenshots/myAccount/footer/footer.spec.js
I want to get rid of this recursive folder structure and save all screenshots inside screenshots folder (so that I can easily access these screenshots and add it to my mochawesome report).
Is there any way to do it ?
Any help will be appreciated and let me know if I was unable to put my question properly. I am willing to add more information.
Yes, you can use the Cypress screenshot API:
for example:
// cypress/plugins/index.js
const fs = require('fs')
module.exports = (on, config) => {
on('after:screenshot', (details) => {
// details will look something like this:
// {
// size: 10248
// takenAt: '2018-06-27T20:17:19.537Z'
// duration: 4071
// dimensions: { width: 1000, height: 660 }
// multipart: false
// pixelRatio: 1
// name: 'my-screenshot'
// specName: 'integration/my-spec.js'
// testFailure: true
// path: '/path/to/my-screenshot.png'
// scaled: true
// blackout: []
// }
// example of renaming the screenshot file
const newPath = '/new/path/to/screenshot.png'
return new Promise((resolve, reject) => {
fs.rename(details.path, newPath, (err) => {
if (err) return reject(err)
// because we renamed/moved the image, resolve with the new path
// so it is accurate in the test results
resolve({ path: newPath })
})
})
})
}
You could also create symlinks if you wanted the image in two places, for example.
I'm developing a Jekyll plugin. When I run the jekyll serve command, site files are regenerated when I change any markdown, html, or plugin files, as expected. The problem I've found is that while markdown/HTML files are regenerated, the plugins themselves are not reloaded. I have to terminate jekyll serve and issue the command again for the plugin changes to go into effect. Is there a way to make it so that the plugins get reloaded automatically when changed?
This is for Jekyll 3.1.2.
Based on the suggestion from #DavidJacquel and the gist I found here, I used Gulp with this gulpfile
'use strict';
var gulp = require('gulp'),
express = require('express'),
spawn = require('child_process').spawn;
var jekyll_file = process.platform === 'win32' ? 'jekyll.bat' : 'jekyll';
gulp.task('jekyll', () => {
var jekyll = spawn(jekyll_file, ['build', '--incremental']);
var output = '';
jekyll.stdout.on('data', (t) => { output += t; });
jekyll.stderr.on('data', (t) => { output += t; });
jekyll.on('exit', (code) => {
if (code)
console.log(`Jekyll exited with code: ${code}\n${output}`);
else
console.log("Finished Jekyll build");
});
});
gulp.task('serve', () => {
var server = express();
server.use(express.static('_site/'));
server.listen(4000);
});
gulp.task('watch', () => {
gulp.watch(['**/*.html', '**/*.md', '_plugins/*.rb', '!_site/**/*'], ['jekyll']);
});
gulp.task('default', ['jekyll', 'serve', 'watch']);
to get the desired effect. Also created issue here.