There are several parts to my answer so I'll try to keep them short as I can.
For environment variables I use a package called node-env-run. You can find it here. It is really easy to setup and allows you to change environment variables on the fly for local dev. You just setup an .env file in the directory you are running the commands from with a list of key/value pairs. Then you run your script like this:
nodenv --exec "ng e2e"
Nodenv will pickup the variables in that file and create the environment variables for the current test run. They are all discarded at the end of the session. It works great for local dev. From there I just setup environment variables in my build tool using the same env variable names as my .env file. Then I reference them in my params object in the protractor config. A good example would be for something like database credentials that may be different based on the environment you are running tests against.
params: {
sql: {
host: process.env.DB_HOST,
dbname: process.env.DB_NAME,
user: process.env.SQL_SERVER_USER,
password: process.env.SQL_SERVER_PASSWORD
}
}
For the second part of your question, how to implement different config files, I just use Object.assign(defaultConf, environmentConf) to accomplish this. The properties in the environmentConf will overwrite the same properties in the defaultConf.
I usually setup a default config that contains all the properties that are going to be common among all the configs. In the environment configs I only put properties that are unique to each environment. An example would be baseUrl. Here is an example of what I mean.
Default Config
module.exports = {
allScriptsTimeout: 11000, // Timeout of each script
specs: [
'../specs/**/*.ts'
],
capabilities: {
browserName: 'chrome',
acceptInsecureCerts : true,
chromeOptions: {
args: [
'--start-maximized'
],
prefs: {
download: {
prompt_for_download: false,
default_directory: path.resolve(__dirname, '../downloads/')
}
}
}
},
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
SELENIUM_PROMISE_MANAGER: false,
onPrepare: function() {
// ...
},
params: { // params object... },
suites: { // suites listed here... }
}
Local Dev Config
module.exports = {
baseUrl: 'http://localhost:8082',
directConnect: true
}
QA Environment Config
module.exports = {
baseUrl: 'https://my-app:7443',
seleniumAddress: 'http://hub:4444/wd/hub',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 60000,
print: function() {}
}
}
As you can see I'm using directConnect for local dev but a selenium hub once the app has been deployed to a given environment. The way I handle this with protractor is I pass in a command line flag --params.env=localhost. Then in the protractor config I get the value of this argument and choose what the config looks like based on that. Given the examples above it would look something like this.
From the command line I would run something similar to this nodenv --exec "ng e2e -- --params.env=localhost" or nodenv --exec "protractor conf.js --params.env=release". And here is what the conf.js would look like:
const env = process.argv.filter(arg => {
return arg.includes('--params.env');
})[0];
let isLocal = false;
let isRelease = false;
if (env) {
isLocal = env.includes('localhost');
isRelease = env.includes('release');
}
const defaultConf = require('./default.conf');
const localConf = require('./local.conf');
const qaEnvConf = require('./qa.conf');
const releaseConf = require('./release.conf');
let protractorConf = {};
// run tests against localhost
if (isLocal) {
protractorConf = Object.assign(defaultConf, localConf);
}
if (isRelease) {
protractorConf = Object.assign(defaultConf, releaseConf);
}
if(!isLocal && !isRelease) {
protractorConf = Object.assign(defaultConf, qaEnvConf);
}
exports.config = protractorConf;
I'm sure there may be better ways to accomplish this but doing it this way allows me to use different configs without having to install another 3rd party dependency. Also, if you want to use the release configuration but run the tests against a staging or prod environment it's simple. Just pass in the baseUrl from the command line and it will overwrite anything that is in the config. nodenv --exec "ng e2e -- --baseUrl=https://my-url/ --params.env=release"