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.