How to check for file in download folder and if exist delete in cypress - cypress

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.

Related

The task 'rp_Log' was not handled in the plugins file. The following tasks are registered: gmail:get-messages

I am writing the cypress test for my website. I have included reportportal js client in my test and my test was running without any issues.
Now I have added gmail-tester for email verification. When I run it I am getting the error
cy.task('rp_Log') failed with the following error:
The task 'rp_Log' was not handled in the plugins file. The following tasks are registered: gmail:get-messages
my plugin/index.js file looks like this
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
/**
* #type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
const registerReportPortalPlugin = require('#reportportal/agent-js-cypress/lib/plugin');
const debug = require('debug');
const path = require('path');
const gmail_tester = require('gmail-tester');
module.exports = (on) => registerReportPortalPlugin(on);
module.exports = (on, config) => {
on("before:browser:launch", (browser = {}, launchOptions) => {
if (browser.name === "chrome"&& browser.isHeadless) {
launchOptions.args.push('--disable-gpu');
return launchOptions;
}
});
on("task", {
"gmail:get-messages": async args => {
const messages = await gmail_tester.get_messages(
path.resolve(__dirname, "credentials.json"),
path.resolve(__dirname, "token.json"),
args.options
);
return messages;
}
});
};
My test file looks like this
describe('Launch website',() => {
it('Home visit',() => {
cy.visit('http://localhost:3000')
cy.log("Visited the page")
cy.screenshot("Launch_name.png")
cy.rp_screenshot("Launch.png")
})
})
When I run the test I can see the my page is getting launched and it's printing the log also. But after that it's telling cy.task('rp_log') is not defined instead it can see the gmail get messages.
can anyone help me to get rid of this error?
I resolved an issue. We cant use two modules.export in index.js file. The answer should look like this
module.exports = (on, config) => {
registerReportPortalPlugin(on);
on("before:browser:launch", (browser = {}, launchOptions) => {
if (browser.name === "chrome"&& browser.isHeadless) {
launchOptions.args.push('--disable-gpu');
return launchOptions;
}
});
on("task", {
"gmail:get-messages": async args => {
const messages = await gmail_tester.get_messages(
path.resolve(__dirname, "credentials.json"),
path.resolve(__dirname, "token.json"),
args.options
);
return messages;
}
});
};

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.
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'))

Cypress: How to test Windows window to Save a Data?

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')

Use package.json version in MD files for Vue Press

I'm trying to utilise the package.json version tag inside of my *.md files which get later compiled into HTML, however I can't seem to figure out how to do this. My plugin.js files contains the following which I thought I could utilise:
const { version } = require('../../package.json')
module.exports = (/*options, ctx*/) => ({
async enhanceAppFiles () {
const code = `export default ({ Vue }) => {
Vue.mixin({
computed: {
$version () {
return '${version}'
}
}
})
}`
return [{
name: 'vuepress-plugin-vue-cli-plugin-p11n',
content: code
}]
}
})
I tried using version and $version inside of my *.md files with little luck, has anyone else got this issue?
The easiest way to achieve this, it's simply put the version into themeConfig and let VuePress do its thing
// .vuepress/config.js
const { version } = require('../../package')
module.exports = {
themeConfig: {
version: version
}
}
and use it in markdown like
{{ $themeConfig.version }}
However, it seems like that themeConfig isn't meant for this, so you can also create your own computed properties
// .vuepress/enhanceApp.js
const { version } = require('../../package')
export default ({ Vue }) => {
Vue.mixin({
computed: {
$version: function() {
return version
}
}
})
}
and use it like
{{ $version }}

Configure screenshot folder in Cypress

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.

Resources