This is a follow-up to the Set firefox profile with protractor topic.
According to the setFirefoxProfile howto, it is possible to set a firefox profile with a special "helper" js code which uses firefox-profile and q libraries to make an encoded firefox profile on the fly.
This worked for me until I've tried to use multiple browsers and configuring multiCapabilities:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
multiCapabilities: [
{
browserName: 'chrome',
specs: [
'footer.disabledCookies.spec.js'
],
chromeOptions: {
prefs: {
'profile.default_content_settings.cookies': 2
}
}
},
...
// other capabilities here
...
helper.getFirefoxProfile()
},
...
}
With this setup I'm getting an error (full traceback here):
Spec patterns did not match any files.
As I understand, this means that the setup with firefox profile is missing specs key. In other words, it cannot find any tests to run.
I've tried to include specs into the capabilities dictionary inside the helper itself, but the error persists.
How to fix the error and set firefox profile if using multiCapabilities?
As a workaround, I've created a separate protractor configuration file with only firefox configured (using capabilities) and set grunt to run protractor twice - one for this "firefox with a profile" config and the other one for all other browsers.
Right now, protractor can only accept promise as capabilities if we are NOT using multicapabilities. The reason for this is because multiCapabilities runs each task in a new process, so the promise (function) cannot be passed (single capabilities work because we're not forking).
Alternatively we could resolve capabilities in the launcher, before passing the resolved capabilities into the new processes; however, this will break the ability to set up proxies (https://github.com/angular/protractor/pull/1040), which relies on capability promises to be resolved after driverProvider setup.
I can't think of an easy way of doing this (without large refactoring), but it is definitely doable.
I created an issue for Protractor (https://github.com/angular/protractor/issues/1594). Please follow that and/or comment on it if this is something you need or you have other ideas to implement it.
For now you would need to use the workaround you mentioned in your original question.
UPDATE
https://github.com/angular/protractor/pull/1629 supports this. Starting in protractor 1.6 (or if you sync to master) you can pass in a function to config.getMultiCapabilities like onPrepare and onCleanup. This function can return a promise to multiCapabilties (i.e. array of capabilities).
See https://github.com/angular/protractor/blob/master/spec/getCapabilitiesConf.js for an example.
Following the pull request sent by #hankduan, here is how have I used getMultiCapabilities() to combine different capabilities where one of them is a promise (needed for firefox-profile to be set):
"use strict";
var FirefoxProfile = require("firefox-profile");
var q = require("q");
exports.config = {
seleniumAddress: "http://127.0.0.1:4444/wd/hub",
getMultiCapabilities: function() {
var deferred = q.defer();
var multiCapabilities = [
{
browserName: "chrome",
specs: [
"footer.disabledCookies.spec.js"
],
chromeOptions: {
prefs: {
"profile.default_content_settings.cookies": 2
}
}
},
{
browserName: "chrome",
specs: [
"*.spec.js"
],
exclude: [
"footer.disabledCookies.spec.js",
"footer.disabledJavascript.spec.js",
"footer.disabledFlash.spec.js"
]
},
{
browserName: "chrome",
specs: [
"footer.disabledFlash.spec.js"
],
chromeOptions: {
args: [
"--disable-internal-flash",
"--disable-bundled-ppapi-flash",
"--disable-plugins-discovery"
]
}
}
];
// Wait for a server to be ready or get capabilities asynchronously.
setTimeout(function() {
var firefoxProfile = new FirefoxProfile();
firefoxProfile.setPreference("javascript.enabled", false);
firefoxProfile.encoded(function (encodedProfile) {
var capabilities = {
"browserName": "firefox",
"firefox_profile": encodedProfile,
"specs": [
"footer.disabledJavascript.spec.js"
]
};
multiCapabilities.push(capabilities);
deferred.resolve(multiCapabilities);
});
}, 1000);
return deferred.promise;
},
...
};
Hope this would help somebody in the future.
Related
I am working with Protractor 5.4.0 and cucumber.
The protractor.conf.js file is:
global.expect = require('chai').expect;
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub', // This is targetting your local running instance of the selenium webdriver
specs: [
'../Features/UI_Tests.feature'
],
capabilities: {
browserName: 'chrome' // You can use any browser you want. On a CI environment you're going to want to use PhantomJS
},
framework: 'custom', //We need this line to use the cucumber framework
frameworkPath: require.resolve('protractor-cucumber-framework'), // Here it is
cucumberOpts: {
//format: 'pretty',
require: '../Features/step_definitions/my_steps.js', // This is where we'll be writing our actual tests
// tags: ['#basic'],
strict: true,
plugin:"json"
},
resultJsonOutputFile:'./testResults.json', //output file path to store the final results in .json format
params: {
env: {
hostname: 'http://0.0.0.0:8000' // Whatever the address of your app is
}
}
};
I have this scenario defined with some examples:
Scenario Outline: dropdown boxes appear and work as expected.
When go to "URL"
Then application is running
When click <box>
Then <option> is present in <box>
Examples:
|box| option|
|templateSelection| Apparent Energy |
|templateDeliveryPathSelection| Email |
|templateLocaleSelection| English |
I am using this piece of code to check that text of the dropdown box is the same one as the option column:
checkDropdown: function (value,dropdown) {
var text = element(by.id(dropdown)).getText();
expect(text).to.eventually.equal(value);
},
It seems to be working properly because the output informs that all the scenarios have passed. However, if we change any of the values in the "option" column to make it fails, the output is the same one, all scenarios pass. Why?
Thanks in advance.
Try:
checkDropdown: function (value,dropdown) {
var text = element(by.id(dropdown)).getText();
return expect(text).to.eventually.equal(value);
}
It's because you aren't returning the expect. You always have to return a promise in your step definitions. if the function returns undefined it will pass regardless.
I highly recommend using https://github.com/canvaspixels/cucumber-protractor if you're using those two technologies to save tons of boilerplate and effort. You can keep your existing tests and migrate gradually.
There's a demo video here: https://www.youtube.com/watch?v=5vuYL4nxMXs
I'm attempting to setup Nightwatch.js for the first time. I'm following the following tutorial: https://github.com/dwyl/learn-nightwatch
Unfortunately I've hit a roadblock, and I'm in need of help resolving it.
Error retrieving a new session from the selenium server.
Connection refused! Is selenium server started?
nightwatch.conf.js
module.exports = {
"src_folders": [
"test"// Where you are storing your Nightwatch e2e/UAT tests
],
"output_folder": "./reports", // reports (test outcome) output by nightwatch
"selenium": {
"start_process": true, // tells nightwatch to start/stop the selenium process
"server_path": "./node_modules/nightwatch/bin/selenium.jar",
"host": "127.0.0.1",
"port": 4444, // standard selenium port
"cli_args": {
"webdriver.chrome.driver" : "./node_modules/nightwatch/bin/chromedriver"
}
},
"test_settings": {
"default": {
"screenshots": {
"enabled": true, // if you want to keep screenshots
"path": './screenshots' // save screenshots here
},
"globals": {
"waitForConditionTimeout": 5000 // sometimes internet is slow so wait.
},
"desiredCapabilities": { // use Chrome as the default browser for tests
"browserName": "chrome"
}
},
"chrome": {
"desiredCapabilities": {
"browserName": "chrome",
"javascriptEnabled": true // set to false to test progressive enhancement
}
}
}
}
guinea-pig.js
module.exports = { // addapted from: https://git.io/vodU0
'Guinea Pig Assert Title': function(browser) {
browser
.url('https://saucelabs.com/test/guinea-pig')
.waitForElementVisible('body')
.assert.title('I am a page title - Sauce Labs')
.saveScreenshot('ginea-pig-test.png')
.end();
}
};
Based on the configuration setup. I kept it as basic as possible. I cannot pinpoint the source where it would suggest another selenium server has started. Any ideas?
EDIT: TIMEOUT ERROR
In your nightwatch.json file, within "selenium"
Make sure your server path is correct.
Make sure your webdriver.chrome.driver path is correct.
Those are specific to your machine. If those do not refer to the correct file in the correct location, you'll get problems starting the selenium server.
After that, you want to make certain that the version of the selenium server you have works with the version of chrome driver you have and that that will work with the version of the Chrome browser you have.
But as Krishnan Mahadevanindicated, without the whole error message, we can't be of much more help.
The solution involved deleting my instance of Chrome (although it was the most recent version) and simply reinstalling the browser again.
I encourage all facing the same problems to first look at QualiT's response above as it's the more conventional troubleshooting strategy.
I had got the same issue when I used vue-cli init on my project. after I updated to Java 9, this problem was resolved.
How can I use copy and paste with protractor on MAC with Chrome?
newInput.sendKeys(protractor.Key.chord(browser.controlKey, "a"));
newInput.sendKeys(protractor.Key.chord(browser.controlKey, "c"));
newInput.sendKeys(protractor.Key.chord(browser.controlKey, "v"));
I have "undefined" when I use this code
I use this code from this post Using cross-platform keyboard shortcuts in end-to-end testing but it doesn't work:
browser.controlKey = protractor.Key.CONTROL; //browser.controlKey is a global variable and can be accessed anywhere in the test specs
browser.getCapabilities().then(function(capabilities){
if(capabilities.caps_.platform === "MAC")
browser.controlKey = protractor.Key.COMMAND;
});
elm.sendKeys(protractor.Key.chord(browser.controlKey, "c"));
This is a known chromedriver problem. Unfortunately, sending keyboard shortcuts from Protractor/WebDriverJS is not going to work on Chrome+Mac.
In our project, we've moved all of the tests that involve using keyboard shortcuts to Firefox:
var firefox_only_specs = [
"../specs/sometest1.spec.js",
"../specs/sometest2.spec.js"
];
exports.config = {
multiCapabilities: [
{
browserName: "chrome",
chromeOptions: {
args: ["incognito", "disable-extensions", "start-maximized"]
},
specs: [
"../specs/*.spec.js"
],
exclude: firefox_only_specs
},
{
browserName: "firefox",
specs: firefox_only_specs
}
],
// ...
}
protractor.Key.COMMAND has been tagged as a wontfix in Protractor's github for MAC. Here is a solution I adapted from keyboard commands for left-handed users
Universal copy+paste alternative working for MAC, LINUX, and WINDOWS:
// This does a select all
element1.sendKeys(protractor.Key.chord(protractor.Key.CONTROL, protractor.Key.SHIFT, protractor.Key.HOME));
// This copies the text
element1.sendKeys(protractor.Key.chord(protractor.Key.CONTROL, protractor.Key.INSERT));
// This pastes it in another element
element2.sendKeys(protractor.Key.chord(protractor.Key.SHIFT, protractor.Key.INSERT));
I already have started a server with webdriver-manager start, but I get this error when I try to run protractor:
Using the selenium server at http://127.0.0.1:4444/wd/hub
[launcher] Running 1 instances of WebDriver
ERROR - Unable to start a WebDriver session.
C:\...\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\atoms\error.js:113
var template = new Error(this.message);
^
UnknownError: unknown error: cannot find Chrome binary
My config file looks like this:
exports.config = {
specs: [
'test/*.js'
],
capabilities: {
'browserName': 'chrome'
},
seleniumAddress: 'http://127.0.0.1:4444/wd/hub'
};
I have also tried pointing to the binary in the capabilities object as well as adding chromeDriver and seleniumServerJar keys to no avail. Any ideas?
According to the relevant github issue, the problem is that chromedriver cannot find chrome browser executeable - on different operating systems it searches for it in different places.
You need to either have chrome installed where chromedriver expects it to be, or specify the path to the chrome executeable in the binary setting:
capabilities: {
"browserName": "chrome",
"chromeOptions": {
binary: "D:/Program Files/Chrome/chrome.exe",
args: [],
extensions: [],
}
},
I generated code using JHipster and had similar error where e2e was not working. I provided binary path. But upon npm run e2e the browser opened and displayed data; in the address bar.
I shuffled and provided the binary at the end of chromeOptions after the args and it worked.
capabilities: {
browserName: 'chrome',
chromeOptions: {
args: process.env.JHI_E2E_HEADLESS
? [ "--headless", "--disable-gpu", "--window-size=800,600" ]
: [ "--disable-gpu", "--window-size=800,600" ],
binary: "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"
}
}
Note: I also had to update the chrome version when an unsupported webdriver version error occurred.
I've been trying to handle the basic authentication during my protractor test. Some hard time on it, so i've found a chrome plugin wich sends automatically my credentials for websites that require basic authentication.
As each time that chromedriver is executed, a new profile is loaded, how can i permanelty add a plugin to my tests? I know that there is https://sites.google.com/a/chromium.org/chromedriver/extensions, but i dont think this very clear.
You need to configure extensions list inside chromeOptions:
capabilities {
'browserName': 'chrome',
'chromeOptions': {
'extensions': ['base64 encoded extension']
}
}
Note that it in extensions, it is important to provide a list of base-64 encoded packed Chrome extension.
To get a base64 encoded extension, you need to read the .ctx extension file and encode the contents with base64. For example, using python:
>>> import base64
>>> data = open('path_to_the_ctx_extension').read()
>>> base64.standard_b64encode(data).decode('UTF-8')
# outputs the encoded chrome extension which you can paste in the config
Or, easier, make a helper.js file using fs and q:
var q = require('q');
var fs = require('fs');
exports.getCapabilities = function (filename) {
var deferred = q.defer();
fs.readFile(filename, function (err, data) {
var capabilities = {
'browserName': 'chrome',
'chromeOptions': {
extensions: [
data.toString('base64')
]
}
};
deferred.resolve(capabilities);
});
return deferred.promise;
};
Then, in your protractor config, use this getCapabilities() function to get capabilities:
var helper = require('./helper.js');
exports.config = {
capabilities: helper.getCapabilities('/path/to/crx/extension'),
...
}
Currently, it works with a single extension, so there is a room for improvement.
Also, look through the following issue in case you have problems:
Setting Chrome Options
Check this: https://github.com/andresdominguez/elementor/blob/master/bin/elementexplorer.js#L194
Here I am loading an extension from a local directory. The extension is not a crx file, but the uncompressed version.
'chromeOptions': {
'args': ['--load-extension=' + extensionPath]
}
Instead of committing the extension with your code and having to load it from disk when you run the tests you might want to consider using the authenticator-browser-extension Node module I have recently open-sourced.
To use the module install it from npm:
npm install --save-dev authenticator-browser-extension
And import in the protractor.conf.js:
const { Authenticator } = require('authenticator-browser-extension');
exports.config = {
capabilities: {
browserName: 'chrome',
chromeOptions: {
extensions: [
Authenticator.for('username', 'password').asBase64()
]
}
},
}
Pro tip: remember not to commit your credentials with your code, consider using env variables instead.
Hope this helps!
Jan