Automatically have browser extension applied on Cypress.io - cypress

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

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

How to run few test suit in browser and few in Nodejs environment Mocha?

I have scenario like this:
const isBrowser = new Function("try {return this===window;}catch(e){ return false;}");
if(isBrowser){
//Run browser specific code
}else {
// run nodejs specific code
}
I am setting up a test environment using Mocha, Chai and istanbul. How can i setup in such a way that few test suits should run on browser and few on NodeJs.
The goal is to get the combined coverage report.
how can I configure the Mocha to run in both browser and in NodeJs environment, using karma or without karma ?
for example:
//this should run in NodeJS Environment
describe('Loader Node Js', () => {
it('Load files from File system', (done) => {
loader.load('file path')
.then((files) => {
done();
});
});
});
//this should run in Browser Environment
describe('Loader Browser', () => {
it('Load files from Server AJAX', (done) => {
loader.load('file url')
.then((files) => {
done();
});
});
})
You should be able to test for Node.js and browser specific globals in your suite.
if (typeof module === 'object') {
//this should run in NodeJS Environment
describe('Loader Node Js', () => {
it('Load files from File system', (done) => {
loader.load('file path')
.then((files) => {
done();
});
});
});
} else {
//this should run in Browser Environment
describe('Loader Browser', () => {
it('Load files from Server AJAX', (done) => {
loader.load('file url')
.then((files) => {
done();
});
});
})
}
You have other options, too, like testing for typeof self === 'undefined', which is true in Node.js and false in a browser.
There are a few related question you may find interesting:
Environment detection: node.js or browser
How to check whether a script is running under node.js?
How to detect if script is running in browser or in Node.js?

Ionic 2 - View is not updating within a Promise

My Ionic app works fine when I started it with my PC at work on my android device. Now I am at home and I pulled everything from github to my private windows PC and then I ran "npm install" and "cordova platform add android" and "ionic run android --device". Now the app does not work like before. I have a page where I load images from a backend server.
<ion-content padding>
Test
{{test}}
<ion-card *ngFor="let image of images" (click)="goToProfilePage(image.hash);">
<img src="{{image.url}}"/>
<div class="card-title">{{image.name}}</div>
<div class="card-subtitle">{{image.address}}, {{image.zip}} {{image.city}}</div>
</ion-card>
</ion-content>
TS:
images: any;
test: any;
constructor(public navCtrl: NavController, public navParams: NavParams, public uiHelper: UiHelper, public api: ApiService, public zone: NgZone) {
this.test = "Test2";
this.loadImages();
}
loadImages() {
this.test = "Test3";
this.uiHelper.showLoading();
this.test = "Test4";
this.api.getImagesForScreen().then(
response => {
this.test = "Test5";
if (response['status'] == constants.API_ON_SUCCESS) {
this.test = "Test6";
console.log("Loaded");
this.zone.run(() => {
this.test = "Test7";
this.images = response['data'];
this.shuffle(this.images);
this.uiHelper.dismissLoading();
});
}
else {
this.uiHelper.dismissLoadingAndPrintApiErrorWithMessage(response['messages']);
}
},
err => {
this.uiHelper.dismissLoadingAndPrintApiError();
}
);
}
The view output is "Test Test4". So it seems like the view is not updating anymore within the promise which is returned from api.getImagesForScreen(). The code should work fine, because if I open chrome://inspect and open the console there is "Loaded" logged. So he definitely should show me "Test6" or "Test7" on the view. The promise on api.getImagesForScreen is created like this:
import {Promise} from 'es6-promise';
...
new Promise((resolve, reject) => {
this.http.get(url).map(res => res.json()).subscribe(
data => {
resolve(data);
},
err => {
reject(err);
}
);
});
Someone can help me with it?
EDIT:
One more weird thing: The problem occurs when I open the site from an other site. If I set this page as the start page everything is working. But when I switch the page and then go back to that page again, it is not working anymore. So it seems the first time where something is loaded from the backend it is working but on the second time it is not working anymore (only the view, because the console still logs the "loaded success"). And there are no errors in console...

Resources