Reputation: 39
We have an E2E project, that is written with Angular CLI 6 and Protractor. Currently we manage our configurations in angular.json:
"configurations": {
"local_chrome": {
"protractorConfig": "./protractor.local.conf.js"
},
"remote_dev_chrome": {
"protractorConfig": "./protractor.remote.dev.chrome.conf.js"
},
"remote_qsa_chrome": {
"protractorConfig": "./protractor.remote.qsa.chrome.conf.js"
},
In package.json we define scripts:
"e2e:local": "ng e2e --configuration=local_chrome --webdriver-update=false",
"e2e:dev:chrome": "ng e2e --configuration=remote_dev_chrome --webdriver-update=false",
"e2e:qsa:chrome": "ng e2e --configuration=remote_qsa_chrome --webdriver-update=false",
And so start we our tests from command line:
npm run e2e:qsa:chrome -- --base-url=https://aut.com --suite=szenarioTests
We want to test on 4 browsers and 5 environments. This means that we need 5*4=20 configuration files. And these files are 90% identical. That is a little bit monstrous and doesn't maintainable.
Does anyone know how can we minimize the number of configuration files and duplications? Are there any best practicies for E2E configuration in Angular CLI? Or maybe Protractor with Angular CLI is not suitable for big projects?
Upvotes: 1
Views: 1311
Reputation: 39
We decided not to use angular cli for E2E tests. As result, we can configure our tests from command line and we have no dublications in config file (easy maintainability).
In our solution we set many parameters per command line (browser, environment, logging level, remote or local). Our implementation is something similar to tehbeardedone solution. We have one base config file and one script that reads command line arguments and set corresponding configuration.
To do that we use
const configuration = process.argv.filter(arg => {
return arg.includes('--browser');
})[0];
and then we use simple if to set configuration. For each parameter we have also default values.
Upvotes: 0
Reputation: 2858
I've done something similar to Ben's example except instead of extending I used Object.assign()
to create my configs.
Create a default config that has all the things that will be shared between configurations. Then in each of the other configs only include the stuff that will be different between configurations. Any duplicate fields will get overwritten by the second argument in Object.assign()
For example, when I am running tests on my local dev environment this is what my local config looks like:
// local.conf.js
module.exports = {
baseUrl: 'http://localhost:8082',
directConnect: true
}
Our environment is all containerized so when I want to run smoke tests on builds this is what the config looks like:
// build.conf.js
module.exports = {
baseUrl: 'https://app:7443',
seleniumAddress: 'http://hub:4444/wd/hub',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
}
}
My default (shared) config doesn't include directConnect
or seleniumAddress
since they cannot be together in the same config. These values come from the other config files. Using the above examples as a reference your base config would look something like this:
const defaultConf = require('/path/to/dafault.conf');
const localConf = require('/path/to/local.conf');
const remoteDevChrome = require('/path/to/remote_dev_chrome.conf');
const remoteQsaChrome = require('/path/to/remote_qsa_chrome.conf');
const configuration = process.argv.filter(arg => {
return arg.includes('--configuration');
})[0];
let protractorConf = {};
switch (configuration.split('=')[1]) {
case 'local_chrome':
protractorConf = Object.assign(defaultConf, localConf);
case 'remote_dev_chrome':
protractorConf = Object.assign(defaultConf, remoteDevChrome);
case 'remote_gsa_chrome':
// ... and so on ...
default:
// whatever default config you use
}
exports.config = protractorConf;
Doing it this way you no longer need to have multiple scripts in your package.json
. You can just use one script and the config will be built based off what you passed in for --configuration
Upvotes: 0
Reputation: 694
I am not sure of a way to minimize the total number of files. However, you can have 1 conf_shared file that all of your other confs extend which will make it easier to maintain in case of changes.
Example conf.js
import {ConfigShared} from "./conf_shared";
let specs = ["YourSpecsHere"];
let capabilities = {browserName:'chrome',...};
class ConfigLocal extends ConfigShared{
specs = specs;
capabilities = capabilities;
}
export const config = new ConfigLocal().exampleFunction(); //can call functions in conf_shared
Example conf_shared
import {Config} from 'protractor';
export class ConfigShared implements Config{
specs: ['']; //will get overriden by conf.js
framework: 'jasmine2';
//rest of shared config goes here
//you can also make function that you will call from conf.js
exampleFunction(){
//do stuff here
}
}
Anything that you have shared between the conf files can go in a conf_shared file which will help with maintainability. If it is stuff that is only shared between certain tests, you can put it in functions (have functions change conf) and then call the functions from conf.js
Upvotes: 1